home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / dskutil / 2m30src.zip / 2MGUI.ASM < prev    next >
Assembly Source File  |  1995-03-06  |  269KB  |  6,550 lines

  1.  
  2. ;┌───────────────────────────────────────────────────────────────────┐
  3. ;│                                                                   │
  4. ;│                   █████ █   █ █████ █   █ █████                   │
  5. ;│                       █ ██ ██ █     █   █   █                     │
  6. ;│                   █████ █ █ █ █ ███ █   █   █                     │
  7. ;│                   █     █   █ █   █ █   █   █                     │
  8. ;│                   █████ █   █ █████ █████ █████    V 1.0          │
  9. ;│                                                                   │
  10. ;│                                                                   │
  11. ;│              CODIGO PARA CREAR Y CONTROLAR DISQUETES              │
  12. ;│           APROVECHANDO LA CAPACIDAD ANTES DE FORMATEAR            │
  13. ;│        EN SISTEMAS PC, XT, AT - ISA/EISA/VLB/PCI (No MCA)         │
  14. ;│          CON CONTROLADORAS Y UNIDADES DE ALTA DENSIDAD            │
  15. ;│                                                                   │
  16. ;│           (C) 1994-1995 Ciriaco García de Celis.                  │
  17. ;│                Email:   ciri@gui.uva.es                           │
  18. ;│                FidoNET  2:341/21.8                                │
  19. ;│                Grupo Universitario de Informática                 │
  20. ;│                Facultad de Ciencias -  Valladolid (España)        │
  21. ;│                                                                   │
  22. ;│      Ensamblar con  TASM 2mgui /m5  y enlazar con TLINK 2mgui     │
  23. ;│        Se necesita el fichero 2MUTIL.INC incluído en 2M 3.0       │
  24. ;│                                                                   │
  25. ;└───────────────────────────────────────────────────────────────────┘
  26.  
  27.  
  28. ; ------------ Constantes fundamentales y valores por defecto.
  29.  
  30. M_DMA          EQU     ON         ; modo DMA por defecto
  31. FRONT          EQU     28         ; pista de división del disco 360DH
  32. GAPDEF         EQU     20         ; GAP anti-FIFO por defecto
  33. MODOWR         EQU     ON         ; por defecto, caché de escritura
  34. W_CACHE_TM     EQU      9         ; escritura retardada: 9/18 segundos
  35. PRE_GAP3       EQU     20         ; GAP3 para preformateo
  36. MPISTA         EQU  30000         ; mayor pista absoluta posible
  37. PISTAS         EQU     82         ; nº pistas por defecto
  38. SECTDEF        EQU    128         ; tamaño de sector lógico por defecto
  39. CLUSDEF        EQU   1024         ; tamaño de clúster por defecto
  40. MINROOT        EQU    128         ; entradas raíz mínimo por defecto
  41. SLID_X         EQU     55         ; sliding X por defecto (en grados)
  42. SLID_Y         EQU     90         ; sliding Y por defecto (en grados)
  43.  
  44. t_525_dd       EQU   6098         ; tamaños recomendados (t_)
  45. m_525_dd       EQU   6250         ; y límites teóricos por pista (m_)
  46. t_525_hd       EQU  10239
  47. m_525_hd       EQU  10416
  48. t_35_dd        EQU   7343
  49. m_35_dd        EQU   7500
  50. t_35_hd        EQU  12313
  51. m_35_hd        EQU  12500
  52. t_35_ed        EQU  24626
  53. m_35_ed        EQU  25000
  54.  
  55. ; ------------ Macros de propósito general.
  56.  
  57. XPUSH          MACRO regmem            ; apilar lista de registros
  58.                  IRP rm, <regmem>
  59.                    PUSH rm
  60.                  ENDM
  61.                ENDM
  62.  
  63. XPOP           MACRO regmem            ; desapilar lista de registros
  64.                  IRP rm, <regmem>
  65.                    POP rm
  66.                  ENDM
  67.                ENDM
  68.  
  69. XPUSHA         MACRO
  70.                  XPUSH <AX, BX, CX, DX, SI, DI, BP>
  71.                ENDM
  72.  
  73. XPOPA          MACRO
  74.                  XPOP  <BP, DI, SI, DX, CX, BX, AX>
  75.                ENDM
  76.  
  77. DDS            MACRO
  78.                PUSH  AX
  79.                MOV   AX,40h
  80.                MOV   DS,AX
  81.                POP   AX
  82.                ENDM
  83.  
  84. DELAY          MACRO                   ; estados de espera
  85.                  JMP SHORT $+2         ; para AT obsoleto
  86.                  JMP SHORT $+2
  87.                ENDM
  88.  
  89. PMICRO         MACRO                   ; retardo de aprox. 15,09 µs
  90.                LOCAL pmicro_iter       ; (exactamente 18/1193180 sg.)
  91. pmicro_iter:   DELAY
  92.                IN    AL,61h            ; Esta macro puede ejecutarse
  93.                AND   AL,10h            ; repetitivamente (se apoya en
  94.                CMP   AL,AH             ; AX) para hacer retardos a
  95.                JE    pmicro_iter       ; través de la temporización
  96.                MOV   AH,AL             ; del refresco de la memoria
  97.                ENDM                    ; dinámica de los AT.
  98.  
  99. ; ------------ Estructuras de datos.
  100.  
  101. cab_PETICION   STRUC                   ; parte inicial común a todos
  102. tamano         DB    ?                 ; los comandos de la cabecera
  103. unidad_disco   DB    ?                 ; de petición
  104. orden_dsp      DB    ?
  105. estado         DW    ?
  106. dos_info       DB    8 DUP (?)
  107. cab_PETICION   ENDS
  108.  
  109. cab_INIT_BBPB  STRUC                   ; para comandos INIT/BUILD_BPB
  110.                DB    (TYPE cab_PETICION) DUP (?)
  111. num_disc_init  DB    ?                 ; número de unidades definidas
  112. fin_resid_desp DW    ?                 ; área que quedará residente
  113. fin_resid_segm DW    ?
  114. bpb_cmd        EQU   THIS DWORD
  115. bpb_cmd_desp   DW    ?                 ; línea de órdenes del CONFIG
  116. bpb_cmd_segm   DW    ?                 ; y puntero al BPB
  117. nuevo_disco    DB    ?                 ; (DOS 3+) (0-A:, 1-B:,...)
  118. cab_INIT_BBPB  ENDS
  119.  
  120. cab_MEDIACHECK STRUC                   ; estructura para MEDIA CHECK
  121.                DB    (TYPE cab_PETICION) DUP (?)
  122. media_descrip  DB    ?                 ; descriptor de medio
  123. cambio         DB    ?                 ; 1: no cambiado, 0FFh:sí, 0:?
  124. cab_MEDIACHECK ENDS
  125.  
  126. cab_READ_WRITE STRUC
  127.                DB    (TYPE cab_PETICION) DUP (?)
  128.                DB    ?                 ; descriptor de medio
  129. transfer_desp  DW    ?                 ; dirección de transferencia
  130. transfer_segm  DW    ?
  131. transfer_sect  DW    ?                 ; nº de sectores a transferir
  132. transfer_sini  DW    ?                 ; primer sector a transferir
  133. cab_READ_WRITE ENDS
  134.  
  135. cab_GEN_IOCTL  STRUC
  136.                DB    (TYPE cab_PETICION) DUP (?)
  137. categoria_cod  DB    ?                 ; código de categoría
  138. func_cod       DB    ?                 ; código de función
  139. copia_ds       DW    ?
  140. offset_cab     DW    ?
  141. ioctl_info     DD    ?                 ; puntero a información
  142. cab_GEN_IOCTL  ENDS
  143.  
  144.                ; --- Estructura con información local a la unidad.
  145.                ;     Contiene información IOCTL, el BPB y otras.
  146.  
  147. InfoBoot       STRUC                ; subestructura auxiliar
  148. vformat        DW    0100h          ; versión 1.0
  149. fformat        DW    0              ; sin flags especiales en esta versión
  150. vunidad2       DB    ?              ; densidad segunda parte del disco
  151. mfrontera      DB    ?              ; frontera divisora
  152. tpista1        DW    ?              ; tamaño físico pistas  0..FRONTERA-1
  153. tpista2        DW    ?              ; tamaño físico pistas FRONTERA..81
  154. idboot         DW    0AA55h         ; ID de sector válido
  155. InfoBoot       ENDS
  156.  
  157. info_unidad    STRUC
  158.                DB    ?                 ; "sectores iguales" o no
  159.                DB    ?                 ; tipo (1-1.2, 7-1.44, 9-2.88)
  160.                DW    ?                 ; detección de cambio
  161. ioctl_pistas   DW    ?                 ; nº pistas
  162. ioctl_id       DB    '2'+'M'           ; tipo de soporte
  163. bytes_sector   DW    ?                 ; BPB: bytes por sector
  164. sect_cluster   DB    ?                 ; BPB: sectores por cluster
  165. sect_reserv    DW    ?                 ; BPB: sectores reservados
  166. num_fats       DB    ?                 ; BPB: número de FATs
  167. entradas_raiz  DW    ?                 ; BPB: entradas en el raíz
  168. num_sect       DW    ?                 ; BPB: nº total de sectores
  169. media_byte     DB    ?                 ; BPB: descriptor de medio
  170. sectores_fat   DW    ?                 ; BPB: sectores por FAT
  171. sectores_pista DW    ?                 ; BPB: sectores por pista
  172. num_cabezas    DW    ?                 ; BPB: cabezas
  173. sects_ocultos  DD    ?                 ; BPB: sectores ocultos
  174.                DD    0                 ; BPB: sectores (32bit)
  175.                DB    11 DUP (0)        ; BPB: restantes campos
  176. unidad         DB    ?         ; unidad física
  177. tipo_drv       DB    0         ; tipo de la disquetera (0 = no hay)
  178. modobios       DB    ON        ; a ON si el disquete no es 2MGUI
  179. controldrv     DB    OFF       ; a ON si el disco lo controla 2MGUI
  180. cambiodisco    DB    ON        ; a ON por defecto para simular cambio
  181. cilindro       DB    ?         ; cilindro del disco a acceder
  182. cabezal        DB    ?         ; cabezal a emplear
  183. vunidad1       DB    ?         ; # velocidad primer medio disco
  184. infb           InfoBoot <>     ; información del BOOT
  185. tsector        DB    ?         ; # LOG2 (tamaño buffer) redondeado
  186. prot_esc       DB    ?         ; ON = disco protegido contra escritura
  187. numserie       DD    12345678h ; número de serie del disco
  188. evol           DB    "NO NAME    "  ; etiqueta de volúmen (BOOT)
  189. fsystem        DB    "FAT12   "     ; sistema de ficheros
  190. info_unidad    ENDS
  191.  
  192. ; ------------ Códigos de modos y órdenes del DMA, FDC,...
  193.  
  194. BIOS_READ      EQU   2
  195. BIOS_WRITE     EQU   3
  196. F_READ         EQU   46h          ; modo DMA para lectura
  197. F_WRITE        EQU   4Ah          ; modo DMA para escritura
  198. F_VERIFY       EQU   42h          ; modo DMA para verificación
  199. F_FORMAT       EQU   01001101b    ; orden de formateo del FDC
  200. TICSTIMEOUT    EQU   9322         ; constante para 2 segundos
  201. FD_STATUS      EQU   3F4h         ; registro de estado
  202. FD_DOR         EQU   3F2h         ; registro de salida digital
  203. FD_DIR         EQU   3F7h         ; registro de entrada digital
  204. FD_DCR         EQU   3F7h         ; registro de control disco
  205.  
  206.  
  207. ; ************ Inicio del área residente.
  208.  
  209. _PRINCIPAL     SEGMENT
  210.                ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
  211.  
  212.                ORG   0
  213.  
  214. ini_residente  EQU   $
  215.  
  216.                DD    -1           ; encadenamiento con otros drivers
  217. tipo_drive     DW    2840h        ; palabra de atributo:
  218.                                   ; bit 15 a 0: dispositivo de bloques
  219.                                   ; bit 14 a 0: sin control IOCTL
  220.                                   ; bit 13 a 1: SIN formato IBM
  221.                                   ; bit 11 a 1: Open/Close/Remove
  222.                                   ; bit  6 a 1: Generic Ioctl
  223.                DW    estrategia   ; rutina de estrategia
  224.                DW    interrupcion ; rutina de interrupción
  225. num_discos     DB    255          ; número de unidades (255 antes
  226.                                   ; de que INIT lo inicialice)
  227.  
  228. ; ***************************************************
  229. ; *                                                 *
  230. ; *   D A T O S    D E L    C O N T R O L A D O R   *
  231. ; *                                                 *
  232. ; ***************************************************
  233.  
  234. ; ------------ Identificación estandarizada del programa.
  235.  
  236. program_id     LABEL BYTE
  237. segmento_real  DW    0   ; segmento real donde será cargado
  238. offset_real    DW    0   ; offset real     "     "     "
  239. longitud_total DW    0   ; zona de memoria ocupada (párrafos)
  240. info_extra     DB    03h ; bits 0, 1 y 2-> 000: normal, con PSP
  241.                          ;                 001: bloque UMB XMS
  242.                          ;                 010: *.SYS
  243.                          ;                 011: *.SYS formato EXE
  244.                          ; bit 7 a 1: «extension_id» definida
  245. multiplex_id   DB    0   ; número Multiplex de este TSR
  246. vectores_id    DW    tabla_vectores
  247. extension_id   DW    0
  248.                DB    "*##*"
  249. autor_nom_ver  DB    "CiriSOFT:2MGUI:1.0",0
  250.  
  251.                DB    3  ; número de vectores de interrupción usados
  252. tabla_vectores EQU   $
  253.                DB    8h            ; INT 8h
  254. ant_int08      LABEL DWORD         ; dirección original
  255. ant_int08_off  DW    0
  256. ant_int08_seg  DW    0
  257.                DB    13h           ; INT 13h
  258. ant_int13      LABEL DWORD         ; dirección original
  259. ant_int13_off  DW    0
  260. ant_int13_seg  DW    0
  261.                DB    2Fh           ; INT 2Fh
  262. ant_int2F      LABEL DWORD         ; dirección original
  263. ant_int2F_off  DW    0
  264. ant_int2F_seg  DW    0
  265.  
  266. ; ------------ Datos de trabajo.
  267.  
  268. pcab_peticion  LABEL DWORD        ; puntero a la cabecera de petición
  269. pcab_pet_desp  DW    0
  270. pcab_pet_segm  DW    0
  271.  
  272. p_rutinas      LABEL WORD         ; tabla de rutinas del controlador
  273.                DW    init
  274.                DW    media_check
  275.                DW    build_bpb
  276.                DW    nofunc
  277.                DW    read
  278.                DW    read_nowait
  279.                DW    input_status
  280.                DW    input_flush
  281.                DW    write
  282.                DW    write_verify
  283.                DW    output_status
  284.                DW    output_flush
  285.                DW    ioctl_output
  286.                DW    open              ; DOS 3.0+
  287.                DW    close             ; DOS 3.0+
  288.                DW    remove            ; DOS 3.0+
  289.                DW    nofunc
  290.                DW    nofunc
  291.                DW    nofunc
  292.                DW    generic_ioctl     ; DOS 3.2+
  293.  
  294. drv_pvars      LABEL WORD              ; punteros a variables y BPB
  295.                DW    info_E
  296.                DW    info_F
  297.  
  298. bpb_ptrs       LABEL WORD              ; tabla de punteros BPB
  299.                DW    info_E.bytes_sector
  300.                DW    info_F.bytes_sector
  301.  
  302. info_E         info_unidad <>          ; 2 BPB's para las 2 unidades
  303. info_F         info_unidad <>          ; posibles ya inicializados y
  304.                                        ; sus variables particulares.
  305.  
  306. info_BUF       info_unidad <>          ; para la pista en el buffer
  307.  
  308. pet_fantasma   cab_READ_WRITE <>       ; cabecera de petición de
  309.                                        ; solicitud fantasma
  310.  
  311.                ; ----- Variables de control globales.
  312.  
  313. unidad_base    DB    ?       ; primera letra de unidad definida
  314. tbase          DW    ?       ; constante para retardos (XT)
  315. pcxt           DB    OFF     ; a ON si no es AT
  316. drdos6         DB    OFF     ; a ON si es DR-DOS 6.0 ó Novell DOS 7.0
  317. tbuffer        DW    ?       ; tamaño del buffer interno en bytes
  318. sbuffer        DW    ?       ; puntero al segmento del buffer
  319. sbuf512        DW    ?       ; copia de seguridad del mismo
  320. ems_handle     DW    0       ; handle EMS (si usado)
  321. marco_ems      DW    ?       ; marco de página EMS (si usado)
  322. ems4           DB    OFF     ; a ON en EMS 4.0+
  323. SYSBYTES       EQU   2       ; en cada pista, NOT(checksum) (2 bytes)
  324. gaprw          DW    GAPDEF  ; GAP R/W simulado
  325. cachewr        DB    MODOWR  ; modo para la caché de escritura
  326. modoDMA        DB    M_DMA   ; modo DMA activo por defecto
  327. sentidoIO      DB    ?       ; F_WRITE ó F_READ según operación NO-DMA
  328. bytesIO        DW    ?       ; bytes para operación NO-DMA
  329. sector_ini     DB    ?       ; número de sector inicial en los accesos
  330. sector_fin     DB    ?       ; número de sector final en los accesos
  331. off_ini        DW    ?       ; # offset inicial en la pista
  332. off_fin        DW    ?       ; # offset final en la pista + 1
  333. bytes          DW    ?       ; # bytes a transferir
  334. wrpend         DB    OFF     ; a ON si pista en buffer aún no escrita
  335. expiraw        DB    ?       ; contador de tics escritura retardada
  336. orden          DB    ?            ; operación READ/WRITE
  337. verificar      DB    OFF          ; a ON si WRITE VERIFY
  338. status         DB    ?            ; resultado de los accesos a disco
  339. fdc_result     DB    7 DUP (?)    ; bytes de resultados del FDC
  340.  
  341.                ; --- Interpretación BIOS de los bits de ST1
  342.  
  343. lista_errs     DB    4            ; 'sector not found'
  344.                DB    0
  345.                DB    10h          ; 'bad CRC'
  346.                DB    8            ; 'DMA overrun'
  347.                DB    0
  348.                DB    4            ; 'sector not found'
  349.                DB    3            ; 'write-protect error'
  350.                DB    2            ; 'address mark not found'
  351.                DB    20h          ; en otro caso: 'bad NEC'
  352.  
  353.  
  354. ; *****************************************************
  355. ; *                                                   *
  356. ; *   C O D I G O    D E L    C O N T R O L A D O R   *
  357. ; *                                                   *
  358. ; *****************************************************
  359.  
  360. ; ------------ Rutina de gestión de INT 2Fh.
  361. ;              También se impide que SMARTDRIVE 4.0+ cachee por
  362. ;              defecto las nuevas unidades (se cuelga al acceder si
  363. ;              los sectores no son de 512 bytes).
  364.  
  365. ges_int2F      PROC  FAR
  366.                STI
  367.                PUSH  CX                ; *
  368.                CMP   AX,4A10h
  369.                JNE   i2f_tsr           ; no llama smartdrive
  370.                CMP   BX,6
  371.                JNE   i2f_tsr           ; no llama smartdrive
  372.                SUB   CL,CS:unidad_base
  373.                DEC   CL
  374.                JZ    no_gracias        ; llama smartdrive
  375.                CMP   CS:info_F.unidad,0
  376.                JE    i2f_tsr           ; no llama para nuestra unidad
  377.                DEC   CL
  378.                JNZ   i2f_tsr           ; no llama para nuestra unidad
  379. no_gracias:    POP   CX                ; *1
  380.                MOV   AX,6              ; nos llama: "No, gracias"
  381.                RETF  2
  382. i2f_tsr:       POP   CX                ; *2
  383.                CMP   AH,CS:multiplex_id
  384.                JE    preguntan
  385.                JMP   CS:ant_int2F      ; saltar al gestor de INT 2Fh
  386. preguntan:     CMP   DI,1992h
  387.                JNE   ret_no_info       ; no llama alguien del convenio
  388.                MOV   AX,ES
  389.                CMP   AX,1492h
  390.                JNE   ret_no_info       ; no llama alguien del convenio
  391.                PUSH  CS
  392.                POP   ES                ; sí llama: darle información
  393.                LEA   DI,autor_nom_ver
  394. ret_no_info:   MOV   AX,0FFFFh         ; "entrada multiplex en uso"
  395.                IRET
  396. ges_int2F      ENDP
  397.  
  398. ; ------------ Rutina de gestión de INT 8. Se utiliza para grabar
  399. ;              en disco el buffer con la pista pendiente de ser
  400. ;              grabada (caché de escritura retardada) si pasa
  401. ;              demasiado tiempo tras el último acceso.
  402.  
  403. ges_int08      PROC  FAR
  404.                CLI                     ; por si llamada con CALL/JMP
  405.                CMP   CS:wrpend,OFF
  406.                JE    bye08
  407.                DEC   CS:expiraw
  408.                JNZ   bye08
  409.                XPUSHA                  ; *
  410.                XPUSH <DS, ES>          ; **
  411.                XPUSH <CS, CS>
  412.                XPOP  <DS, ES>
  413.                MOV   AL,20h
  414.                OUT   20h,AL            ; para que funcione IRQ6 ;-)
  415.                CALL  abs_flush
  416.                XPOP  <ES, DS>          ; **
  417.                XPOPA                   ; *
  418. bye08:         JMP   CS:ant_int08
  419. ges_int08      ENDP
  420.  
  421. ; ------------ Rutina de gestión de INT 13h. Se utiliza para simular
  422. ;              cambios de disco tanto en las nuevas unidades como en
  423. ;              las normales, cuando el usuario conmuta entre ambas,
  424. ;              ya que el primer acceso desde una de ellas baja la
  425. ;              línea de cambio y ésta es la única manera de asegurar
  426. ;              que la información del disco se corresponde con éste
  427. ;              y no con otro antiguo ya sustituído.
  428.  
  429. ges_int13      PROC  FAR
  430.                STI
  431.                CMP   DL,2
  432.                JB    ges_swp
  433. bios13:        JMP   CS:ant_int13
  434. ges_swp:       CMP   AH,2
  435.                JB    bios13
  436.                CMP   AH,16h
  437.                JE    simcamb?
  438.                CMP   AH,5
  439.                JA    bios13
  440. simcamb?:      PUSH  BX
  441.                LEA   BX,info_E               ; apuntar datos unidad
  442.                CMP   CS:[BX].unidad,DL
  443.                JE    tab_dat_ok
  444.                LEA   BX,info_F
  445.                CMP   CS:[BX].unidad,DL
  446.                JE    tab_dat_ok
  447.                POP   BX
  448.                JMP   bios13
  449. tab_dat_ok:    CMP   CS:[BX].controldrv,ON
  450.                MOV   CS:[BX].controldrv,OFF  ; simular cambio de disco
  451.                MOV   CS:[BX].cambiodisco,ON  ; en nueva unidad
  452.                POP   BX
  453.                JNE   bios13
  454.                STC
  455.                MOV   AH,6
  456.                RET   2                       ; y en la A: ó B:
  457. ges_int13      ENDP
  458.  
  459. ; ------------ Rutina de estrategia.
  460.  
  461. estrategia     PROC  FAR
  462.                MOV   CS:pcab_pet_desp,BX
  463.                MOV   CS:pcab_pet_segm,ES
  464.                RET
  465. estrategia     ENDP
  466.  
  467. ; ------------ Rutina de interrupción.
  468.  
  469. interrupcion   PROC  FAR
  470.                STI
  471.                XPUSHA
  472.                XPUSH <DS, ES>
  473.                LDS   BX,CS:pcab_peticion
  474.                MOV   AL,[BX].orden_dsp ; AL = orden
  475.                MOV   AH,0              ; AX = orden
  476.                CMP   AL,13h
  477.                JBE   orden_ok          ; orden soportada
  478.                MOV   AX,8103h          ; orden desconocida
  479.                JMP   exit_interr
  480. orden_ok:      SHL   AX,1              ; orden = orden * 2
  481.                MOV   DI,AX
  482.                ADD   DI,OFFSET p_rutinas
  483.                LEA   SI,drv_pvars
  484.                MOV   AL,[BX].unidad_disco
  485.                CMP   AL,CS:num_discos
  486.                JB    disco_ok
  487.                MOV   AX,8101h          ; unidad desconocida
  488.                JMP   exit_interr
  489. disco_ok:      MOV   AH,0
  490.                SHL   AX,1
  491.                ADD   SI,AX
  492.                MOV   SI,CS:[SI]        ; SI -> BPB y juego variables
  493.                XPUSH <BX,DS>
  494.                CALL  CS:[DI]           ; ejecutar orden
  495.                XPOP  <DS,BX>
  496. exit_interr:   MOV   [BX].estado,AX
  497.                XPOP  <ES, DS>
  498.                XPOPA
  499.                RET
  500. interrupcion   ENDP
  501.  
  502. ; ------------ Las rutinas que controlan el dispositivo devuelven AX
  503. ;              con la palabra de estado. Pueden cambiar todos los
  504. ;              registros, incluídos los de segmento. A la entrada,
  505. ;              DS:BX apunta a la cabecera de petición de solicitud y
  506. ;              CS:SI al BPB y las variables de la unidad invocada.
  507.  
  508. read_nowait:                           ; órdenes ignoradas...
  509. input_status:
  510. input_flush:
  511. output_status:
  512. output_flush:
  513. ioctl_output:
  514. open:
  515. close:
  516. remove:                                ; dispositivo removible
  517. retorno_ok:    MOV   AX,100h
  518.                RET
  519.  
  520. nofunc:        MOV   AX,8103h          ; orden no soportada
  521.                RET
  522.  
  523.                ; --- Soporte IOCTL.
  524.                ;     - Implementa las funciones:
  525.                ;         60h - Obtener parámetros del dispositivo
  526.                ;         66h - Devolver nº de serie (para el DIR)
  527.                ;         41h - Escritura de pista (para DISKCOPY)
  528.                ;         61h - Lectura de pista (para DISKCOPY)
  529.                ;     - Ignora las funciones:
  530.                ;         40h - Establecer parámetros del dispositivo
  531.                ;         46h - Establecer nº de serie
  532.                ;     - Indica siempre que no está permitido:
  533.                ;         42h - Formatear y verificar pista
  534.                ;         62h - Verificar pista
  535.                ;     - Retorna error de "no soportado" en las demás
  536.  
  537. generic_ioctl: LDS   BX,CS:pcab_peticion
  538.                CMP   [BX].categoria_cod,8
  539.                JNE   gen_ioctl_rtf
  540.                MOV   AL,[BX].func_cod
  541.                CMP   AL,60h                 ; soportado subcódigo 60h
  542.                JE    get_devp
  543.                CMP   AL,66h                 ; 66h
  544.                JE    get_serie
  545.                CMP   AL,46h                 ; 46h
  546.                JE    set_serie
  547.                CMP   AL,40h                 ; 40h
  548.                JE    set_devp
  549.                CMP   AL,41h                 ; 41h
  550.                JE    wr_ioctl
  551.                CMP   AL,61h                 ; y 61h
  552.                JE    rd_ioctl
  553.                CMP   AL,42h
  554.                JE    ioct_nosup
  555.                CMP   AL,62h
  556.                JE    ioct_nosup
  557. gen_ioctl_rtf: MOV   AX,8103h               ; orden no soportada
  558.                RET
  559. get_devp:      LES   DI,[BX].ioctl_info     ; orden 0860h invocada
  560.                TEST  BYTE PTR ES:[DI],1
  561.                JZ    devp                   ; no acceder a disco
  562.                XPUSHA
  563.                XPUSH <DS, ES>
  564.                CALL  build_bpb              ; actualizar datos
  565.                XPOP  <ES, DS>
  566.                XPOPA
  567. devp:          INC   SI
  568.                INC   DI
  569.                MOV   CX,38
  570.                PUSH  CS
  571.                POP   DS
  572.                CLD
  573.                REP   MOVSB
  574. set_devp:      JMP   gen_ioctl_ret          ; subcódigo 40h ignorado
  575. get_serie:     LES   DI,[BX].ioctl_info
  576.                ADD   DI,2
  577.                PUSH  CS
  578.                POP   DS
  579.                LEA   SI,[SI].numserie
  580.                MOV   CX,23
  581.                CLD
  582.                REP   MOVSB             ; devolver nº serie y demás
  583. set_serie:     JMP   gen_ioctl_ret     ; no implementado cambiarlo
  584. ioct_nosup:    LES   DI,[BX].ioctl_info
  585.                MOV   BYTE PTR ES:[DI],2
  586.                MOV   AX,8107h          ; no soportado format/verify
  587.                RET
  588. gen_ioctl_ret: MOV   AX,100h           ; Ok
  589.                RET
  590. wr_ioctl:      CALL  ioctl_io_info
  591.                AND   AX,AX
  592.                JNZ   noserie
  593.                MOV   AX,ES:[DI+39]     ; actualizar número de
  594.                MOV   CX,ES:[DI+41]     ; serie en memoria
  595.                LEA   DI,[SI].numserie
  596.                MOV   CS:[DI],AX
  597.                MOV   CS:[DI+2],CX
  598. noserie:       CALL  io_drdos
  599.                CALL  write
  600.                RET
  601. rd_ioctl:      CALL  ioctl_io_info
  602.                CALL  io_drdos
  603.                CALL  read
  604.                RET
  605.  
  606. ioctl_io_info: LES   DI,[BX].ioctl_info
  607.                MOV   AX,ES:[DI+3]           ; cilindro
  608.                MUL   CS:[SI].num_cabezas
  609.                ADD   AX,ES:[DI+1]           ; cabezal
  610.                MUL   CS:[SI].sectores_pista
  611.                ADD   AX,ES:[DI+5]           ; AX = sector inicial
  612.                MOV   CX,ES:[DI+7]           ; CX = número sectores
  613.                LES   DI,ES:[DI+9]           ; ES:DI = dirección E/S
  614.                PUSH  CS
  615.                POP   DS
  616.                LEA   BX,pet_fantasma
  617.                MOV   [BX].transfer_desp,DI
  618.                MOV   [BX].transfer_segm,ES
  619.                MOV   [BX].transfer_sect,CX  ; nº sectores
  620.                MOV   [BX].transfer_sini,AX  ; primer sector
  621.                RET
  622.  
  623.                ; --- El diskcopy de DR-DOS 6.0+ empieza a copiar
  624.                ;     por el final, descendentemente.  Para evitar la
  625.                ;     inevitable recalibración en cada pista al tener
  626.                ;     que ir una pista atrás, se copia al revés ;-)
  627.  
  628. io_drdos       PROC
  629.                CMP   drdos6,ON
  630.                JNE   io_dr_ok
  631.                CMP   [SI].sectores_pista,1
  632.                JNE   io_dr_ok               ; no es un disco 2MGUI
  633.                MOV   AX,[SI].num_sect
  634.                SUB   AX,[BX].transfer_sini
  635.                SUB   AX,[BX].transfer_sect
  636.                MOV   [BX].transfer_sini,AX  ; sector opuesto
  637. io_dr_ok:      RET
  638. io_drdos       ENDP
  639.  
  640. ; ------------ Rutina de detección de cambio de disco.
  641.  
  642. media_check:   CMP   CS:[SI].cambiodisco,ON
  643.                MOV   CS:[SI].cambiodisco,OFF
  644.                MOV   CS:[SI].controldrv,ON
  645.                MOV   AL,0FFh           ; supuesto cambio de disco
  646.                JE    set_cambio        ; disco recién formateado
  647.                MOV   DL,CS:[SI].unidad
  648.                CALL  leer_lin_camb     ; en 1.2M/1.44M/2.88M...
  649.                JNZ   set_cambio
  650.                MOV   AL,1              ; sin cambio de disco
  651. set_cambio:    MOV   [BX].cambio,AL
  652.                MOV   AX,100h
  653.                RET
  654.  
  655. ; ------------ Devolver ZF=1 si la línea de cambio de disco está
  656. ;              inactiva. A la entrada, DL contiene la unidad. El
  657. ;              motor es puesto en marcha y, si no lo estaba ya, la
  658. ;              variable que indica lo que resta para detenerlo
  659. ;              es llevada a su valor normal, por lo que el disco no
  660. ;              tardará mucho en detenerse (incluso sin quizá haber
  661. ;              acelerado aún).
  662.  
  663. leer_lin_camb  PROC
  664.                XPUSHA                  ; *
  665.                PUSH  DS
  666.                DDS
  667.                MOV   AL,1
  668.                MOV   CL,DL
  669.                SHL   AL,CL             ; bit de motor en 0..3
  670.                TEST  DS:[3Fh],AL
  671.                JNZ   rodando           ; el motor ya está girando
  672.                CLC
  673.                CALL  motor_off_cnt     ; cuenta normal detención motor
  674. rodando:       MOV   AH,DL
  675.                MOV   CL,4
  676.                SHL   AH,CL
  677.                OR    AH,AL             ; AH = byte BIOS
  678.                SHL   AL,CL
  679.                OR    AL,00001100b      ; modo DMA, no hacer reset
  680.                OR    AL,DL             ; AL para reg. salida digital
  681.                MOV   DX,FD_DOR
  682.                CLI
  683.                MOV   DS:[3Fh],AH       ; actualizar variable BIOS
  684.                OUT   DX,AL             ; arrancado motor en la unidad
  685.                ADD   DX,5
  686.                DELAY
  687.                IN    AL,DX             ; leer línea de cambio de disco
  688.                STI
  689.                TEST  AL,80h            ; ZF=0 -> cambio de disco
  690.                POP   DS
  691.                XPOPA                   ; *
  692.                RET
  693. leer_lin_camb  ENDP
  694.  
  695. ; ------------ Como el disco no es de tipo IBM, el DOS no intentará
  696. ;              leer el primer sector de la FAT después de invocar
  697. ;              media_check y antes de invocar build_bpb.
  698.  
  699. build_bpb:     XPUSH <CS, CS>
  700.                XPOP  <DS, ES>
  701.  
  702.                CALL  abs_flush         ; liquidar escritura pendiente
  703.  
  704. det_media:     MOV   [SI].cilindro,0
  705.                MOV   [SI].cabezal,0
  706.                MOV   [SI].vunidad1,0
  707.                MOV   [SI].infb.vunidad2,0
  708.                STC
  709.                CALL  reset_drv
  710.                CALL  motor_ok
  711.                CALL  seek_drv
  712.  
  713.                MOV   [SI].tsector,7    ; todo menos 2.88M
  714.                MOV   CX,2
  715. intenta_2mg:   CLC
  716.                CALL  reset_drv
  717.                XOR   DX,DX             ; empezar por alta densidad
  718. densidad_2mg?: MOV   [SI].vunidad1,DL
  719.                MOV   [SI].infb.vunidad2,DH
  720.  
  721.                CALL  detect_2mgui
  722.                JE    detectado_2mg
  723.                TEST  status,80h
  724.                JNZ   proc_bios         ; ¿unidad no preparada?
  725.                ADD   DX,0101h
  726.                CMP   DL,3
  727.                JBE   densidad_2mg?     ; buscar densidad
  728.                LOOP  intenta_2mg
  729.                JMP   proc_bios
  730.  
  731. detectado_2mg: XPUSH <AX, BX, DI>      ; *
  732.  
  733.                MOV   [SI].prot_esc,OFF ; supuesto no protegida...
  734.                CALL  test_st3
  735.                JNC   baja_lc
  736.                MOV   [SI].prot_esc,ON  ; protegida contra escritura
  737.  
  738. baja_lc:       MOV   [SI].cilindro,1
  739.                CALL  seek_drv
  740.                MOV   [SI].cilindro,0
  741.                CALL  seek_drv          ; bajar línea cambio de disco
  742.                MOV   DX,FD_DIR
  743.                IN    AL,DX             ; leer línea de cambio de disco
  744.                MOV   AH,80h
  745.                TEST  AL,AH             ; ZF=0 -> cambio de disco
  746.                XPOP  <DI, BX, AX>      ; *
  747.                JNZ   no_listo
  748.                JMP   s0_2mg_ok
  749.  
  750. proc_bios:     MOV   CX,3
  751. intenta_bios:  CALL  detect_bios       ; intentar acceso BIOS
  752.                JNC   s0_bios_ok
  753.                LOOP  intenta_bios
  754. no_listo:      CMP   AH,80h
  755.                JE    proc_err          ; unidad no preparada
  756.  
  757.                CLC
  758.                CALL  reset_drv
  759.                CALL  motor_ok
  760.                CALL  seek_drv
  761.                MOV   [SI].tsector,8    ; ¿será 2.88M?
  762.                MOV   CX,2
  763. intenta_2mg28: MOV   DX,0303h          ; sólo extraalta densidad
  764.                MOV   [SI].vunidad1,DL
  765.                MOV   [SI].infb.vunidad2,DH
  766.                CALL  detect_2mgui
  767.                JE    detectado_2mg
  768.                LOOP  intenta_2mg28
  769.  
  770.                MOV   AL,20h            ; indicar 'anomalía general'
  771. proc_err:      CALL  errbios2dos
  772.                MOV   [SI].modobios,ON  ; disco no-2MGUI
  773.                RET
  774. s0_2mg_ok:     MOV   [SI].modobios,OFF ; disco 2MGUI
  775.                MOV   AL,7              ; log2 (16384) - 7 = 7
  776.                CMP   [SI].infb.tpista1,16384
  777.                JBE   tsec_ok
  778.                INC   AL                ; log2 (32768) - 7 = 8
  779. tsec_ok:       MOV   [SI].tsector,AL
  780.                MOV   DS,sbuffer
  781.                MOV   BX,11
  782.                JMP   s0_dos
  783. s0_bios_ok:    MOV   [SI].modobios,ON  ; disco no-2MGUI
  784.                MOV   DS,sbuffer
  785.                MOV   BX,11             ; offset en BOOT para el BPB
  786.                CMP   WORD PTR [BX],512 ; ¿sectores de 512?
  787.                JE    s0_dos
  788.                MOV   AX,8107h          ; 'medio físico desconocido'
  789.                RET
  790. s0_dos:        PUSH  SI                     ; *
  791.                LEA   DI,[SI].bytes_sector
  792.                LEA   SI,[SI].numserie
  793.                XCHG  SI,BX             ; SI -> BPB del sector
  794.                MOV   CX,17
  795.                XPUSH <SI, DI>
  796.                CLD
  797.                REP   MOVSB             ; construir BPB...
  798.                XPOP  <DI, SI>
  799.                PUSH  DI
  800.                MOV   DI,BX
  801.                ADD   SI,28             ; apuntar al nº serie y demás
  802.                MOV   CX,23
  803.                REP   MOVSB             ; anotarlo
  804.                POP   DI
  805.                POP   SI                     ; *
  806.                MOV   AX,ES:[SI].sectores_pista
  807.                MUL   ES:[SI].num_cabezas
  808.                MOV   CX,AX
  809.                MOV   AX,ES:[SI].num_sect
  810.                XOR   DX,DX
  811.                DIV   CX
  812.                MOV   ES:[SI].ioctl_pistas,AX
  813.                LDS   BX,CS:pcab_peticion
  814.                MOV   [BX].bpb_cmd_desp,DI   ; nuevo BPB obtenido
  815.                MOV   [BX].bpb_cmd_segm,CS
  816.                MOV   AX,100h                ; Ok.
  817.                RET
  818.  
  819.                ; --- Detectar un disco 2MGUI y devolver AX=tpista1
  820.                ;     y BX=tpista2
  821.  
  822. detect_2mgui:  XPUSH <CX, DX>
  823.                MOV   info_BUF.unidad,-1
  824.                MOV   [SI].cilindro,0
  825.                MOV   [SI].cabezal,0
  826.                MOV   AX,sbuf512
  827.                MOV   sbuffer,AX             ; no usar EMS para esto
  828.                MOV   [SI].infb.tpista1,512  ; con 512 bytes basta
  829.                MOV   [SI].infb.mfrontera,86
  830.                PUSH  ES                ; *
  831.                MOV   ES,sbuffer
  832.                MOV   ES:[PINFOBOOT].idboot,0
  833.                POP   ES                ; *
  834.                CLC
  835.                CALL  reset_drv
  836.                CALL  motor_ok
  837.                CALL  seek_drv
  838.                CALL  lee_pista
  839.                CALL  anotar_acceso
  840.                XPUSH <DS, ES, SI>      ; **
  841.                PUSH  DS
  842.                POP   ES
  843.                MOV   DS,sbuffer
  844.                LEA   DI,[SI].infb
  845.                MOV   SI,PINFOBOOT
  846.                MOV   CX,(TYPE InfoBoot) - 2  ; respetar marca 0xAA55
  847.                CLD
  848.                REP   MOVSB             ; anotar información física BOOT
  849.                CMP   WORD PTR DS:[PINFOBOOT].idboot,0AA55h  ; ¿2MGUI?
  850.                XPOP  <SI, ES, DS>      ; **
  851.                XPOP  <DX, CX>          ; *
  852.                RET
  853.  
  854.                ; --- Detectar un disco estándar.
  855.  
  856. detect_bios:   PUSH  CX                ; *
  857.                MOV   AH,0
  858.                MOV   DL,[SI].unidad
  859.                PUSHF
  860.                CALL  CS:ant_int13        ; reset de disco
  861. media_detect:  MOV   info_BUF.unidad,-1  ; invalidar buffer
  862.                PUSH  ES                  ; **
  863.                MOV   ES,sbuffer
  864.                XOR   BX,BX
  865.                MOV   DL,[SI].unidad
  866.                MOV   DH,0
  867.                MOV   CX,1
  868.                MOV   AX,201h
  869.                PUSHF
  870.                CALL  CS:ant_int13      ; leer sector de arranque
  871.                POP   ES                ; **
  872.                POP   CX                ; *
  873.                RET
  874.  
  875.                ; --- Comprobar ST3 para saber si el disco está
  876.                ;     protegido contra escritura.
  877.  
  878. test_st3       PROC
  879.                PUSH  AX
  880.                MOV   AL,4              ; comando para leer ST3
  881.                CALL  fdc_write
  882.                JC    st3_ok
  883.                MOV   AL,[SI].cabezal
  884.                SHL   AL,1
  885.                SHL   AL,1
  886.                OR    AL,[SI].unidad
  887.                CALL  fdc_write         ; enviar HD, US1, US0
  888.                JC    st3_ok
  889.                CALL  fdc_read
  890.                JC    st3_ok
  891.                TEST  AL,64             ; ¿protegido contra escritura?
  892.                JZ    st3_ok
  893.                POP   AX
  894.                STC
  895.                RET
  896. st3_ok:        POP   AX
  897.                CLC
  898.                RET
  899. test_st3       ENDP
  900.  
  901. ; ------------ Realizar lecturas y escrituras.
  902.  
  903. read:          MOV   CS:verificar,OFF
  904.                MOV   CS:orden,BIOS_READ
  905.                JMP   prepara_io
  906.  
  907. write_verify:  MOV   CS:verificar,ON
  908.                MOV   CS:orden,BIOS_WRITE
  909.                JMP   prepara_io
  910.  
  911. write:         MOV   CS:verificar,OFF
  912.                MOV   CS:orden,BIOS_WRITE
  913.  
  914. prepara_io     PROC
  915.                LES   DI,DWORD PTR [BX].transfer_desp  ; dirección
  916.                MOV   CX,[BX].transfer_sect            ; nº sectores
  917.                MOV   BX,[BX].transfer_sini            ; primer sector
  918.                PUSH  CS
  919.                POP   DS
  920.                ADD   BX,CX
  921.                JNC   io_ok?            ; último sector < 65536
  922. io_no_ok:      MOV   AX,8108h          ; error 'sector no encontrado'
  923.                RET
  924. io_ok?:        CMP   BX,[SI].num_sect
  925.                JA    io_no_ok          ; sector final ¡fuera!
  926.                SUB   BX,CX             ; BX = primer sector
  927. prepara_io     ENDP
  928.                CMP   [SI].modobios,ON
  929.                JE    calcula_dir       ; disco soportado por la BIOS
  930.                CMP   ems_handle,0      ; disco soportado por 2MGUI
  931.                JNE   acc_ems
  932.                JMP   rwv2mgui          ; no usada memoria EMS
  933. acc_ems:       MOV   DX,ems_handle     ; usada memoria EMS
  934.                MOV   AH,47h
  935.                XPUSH <BX, CX, SI, DI>
  936.                INT   67h               ; preservar el contexto
  937.                XPOP  <DI, SI, CX, BX>
  938.                CMP   AH,82h
  939.                JE    acc_ems           ; reintentar
  940.                AND   AH,AH
  941.                MOV   AX,810Ch          ; fallo: anomalía general
  942.                JNZ   rt_acc
  943.                CALL  rwv2mgui
  944.                PUSH  AX
  945. rrst:          MOV   DX,CS:ems_handle  ; ¡DS corrompido si error!
  946.                MOV   AH,48h
  947.                INT   67h               ; restaurar el contexto
  948.                CMP   AH,82h
  949.                JE    rrst              ; reintentar; si falla, pasar
  950.                POP   AX
  951. rt_acc:        RET
  952.  
  953. calcula_dir    PROC
  954.                MOV   AX,[SI].sectores_pista
  955.                MUL   [SI].num_cabezas
  956.                XCHG  AX,BX
  957.                XOR   DX,DX
  958.                DIV   BX                ; AX = cilindro, DX = resto
  959.                MOV   [SI].cilindro,AL
  960.                MOV   AX,DX
  961.                XOR   DX,DX
  962.                DIV   [SI].sectores_pista  ; AX = cabezal, DX = sector
  963.                MOV   [SI].cabezal,AL
  964.                INC   DL
  965.                MOV   sector_ini,DL
  966. calcula_dir    ENDP
  967.  
  968. procesa_io     PROC
  969.                MOV   AX,[SI].sectores_pista
  970.                SUB   AL,sector_ini
  971.                INC   AL                ; AX sectores hasta fin pista
  972. final:         CMP   AL,CL
  973.                JBE   nsect_fp
  974.                MOV   AL,CL             ; ¡no hay que acceder a tantos!
  975. nsect_fp:      MOV   AH,sector_ini
  976.                ADD   AH,AL
  977.                DEC   AH
  978.                MOV   sector_fin,AH     ; sector ini/fin inicializados
  979.                PUSH  DS                ; *
  980.                XOR   BX,BX
  981.                MOV   DS,BX
  982.                LDS   BX,DS:[1Eh*4]     ; DS:BX -> tabla base disco
  983.                CMP   [BX+4],AH
  984.                JAE   ultsec_ok
  985.                MOV   [BX+4],AH         ; sectores/pista necesarios
  986. ultsec_ok:     MOV   BYTE PTR DS:[BX+5],1  ; GAP R/W mínimo
  987.                POP   DS                ; *
  988.                XOR   AH,AH
  989.                SUB   CX,AX             ; restar los que se accederán
  990.                PUSH  CX
  991.                MOV   CX,3              ; 3 intentos como máximo
  992. reintentar_io: PUSH  CX
  993.                MOV   AH,orden
  994.                MOV   CL,sector_ini
  995.                MOV   AL,sector_fin
  996.                SUB   AL,CL
  997.                INC   AL
  998.                MOV   CH,[SI].cilindro
  999.                MOV   DH,[SI].cabezal
  1000.                MOV   DL,[SI].unidad
  1001.                MOV   BX,DI
  1002.                PUSH  AX
  1003.                PUSHF
  1004.                CALL  ant_int13
  1005.                POP   BX
  1006.                JC    fallo_io          ; ha habido fallo
  1007.                CMP   verificar,ON
  1008.                CLC
  1009.                JNE   io_ok
  1010.                MOV   AH,4              ; verificar en write verify
  1011.                MOV   CL,sector_ini
  1012.                MOV   AL,sector_fin
  1013.                SUB   AL,CL
  1014.                INC   AL
  1015.                MOV   CH,[SI].cilindro
  1016.                MOV   DH,[SI].cabezal
  1017.                MOV   DL,[SI].unidad
  1018.                MOV   BX,DI
  1019.                PUSH  AX
  1020.                PUSHF
  1021.                CALL  ant_int13
  1022.                POP   BX
  1023.                JC    fallo_io
  1024.                JMP   io_ok
  1025. fallo_io:      POP   CX
  1026.                CMP   AH,3
  1027.                JE    proc_io_nok       ; protegido contra escritura
  1028.                TEST  AH,80h
  1029.                JNZ   proc_io_nok       ; unidad no preparada
  1030.                MOV   AH,0
  1031.                PUSH  CX
  1032.                PUSHF
  1033.                CALL  ant_int13         ; reset de disco
  1034.                POP   CX
  1035.                LOOP  reintentar_io
  1036.                JMP   proc_io_nok       ; agotadas las oportunidades
  1037. io_ok:         MOV   AH,BL
  1038.                SHL   AH,1
  1039.                MOV   AL,0
  1040.                ADD   DI,AX             ; ES:BX++
  1041.                POP   CX                ; contador de intentos
  1042.                POP   CX                ; sectores que restan
  1043.                JCXZ  fin_io            ; ¿más sectores a transferir?
  1044.                MOV   sector_ini,1      ; ahora desde el primer sector
  1045.                INC   [SI].cabezal      ; de la siguiente cara
  1046.                MOV   AX,[SI].num_cabezas
  1047.                CMP   [SI].cabezal,AL
  1048.                JAE   pr_step
  1049.                JMP   procesa_io
  1050. pr_step:       MOV   [SI].cabezal,0    ; o desde la primera cara
  1051.                INC   [SI].cilindro     ; del siguiente cilindro
  1052.                JMP   procesa_io
  1053. fin_io:        MOV   AX,100h           ; Ok.
  1054.                RET
  1055. proc_io_nok:   POP   CX
  1056.                LDS   BX,pcab_peticion
  1057.                MOV   [BX].transfer_sect,0  ; movidos 0 sectores
  1058.                MOV   AH,1
  1059.                MOV   DL,CS:[SI].unidad
  1060.                PUSHF
  1061.                CALL  CS:ant_int13      ; obtener código de error BIOS
  1062.                CALL  errbios2dos
  1063.                RET                     ; retornar con código error DOS
  1064. procesa_io     ENDP
  1065.  
  1066. ; ------------ Traducir el error BIOS a código de error DOS.
  1067.  
  1068. errbios2dos    PROC
  1069.                MOV   AL,0
  1070.                CMP   AH,3              ; ¿protegido contra escritura?
  1071.                JE    err_dos_ok
  1072.                MOV   AL,8
  1073.                CMP   AH,4              ; ¿sector no encontrado?
  1074.                JE    err_dos_ok
  1075.                MOV   AL,0Fh
  1076.                CMP   AH,6              ; ¿cambio de disco no permitido?
  1077.                JE    err_dos_ok
  1078.                MOV   AL,4
  1079.                TEST  AL,10h            ; ¿error de CRC?
  1080.                JNZ   err_dos_ok
  1081.                MOV   AL,6
  1082.                TEST  AH,40h            ; ¿fallo posicionando cabezal?
  1083.                JNZ   err_dos_ok
  1084.                MOV   AL,2
  1085.                TEST  AH,80h            ; ¿unidad no preparada?
  1086.                JNZ   err_dos_ok
  1087.                MOV   AL,0Ch            ; otro fallo: anomalía general
  1088. err_dos_ok:    MOV   AH,81h
  1089.                RET
  1090. errbios2dos    ENDP
  1091.  
  1092. ; ------------ Lectura, escritura y verificación en disco 2MGUI.
  1093. ;              A la entrada, ES:DI=dirección, BX=sectini, CX=nsects.
  1094.  
  1095. rwv2mgui       PROC
  1096.                MOV   AX,[SI].bytes_sector
  1097.                MUL   BX                ; DX:AX = sector * tamaño
  1098.                XPUSH <CX, AX, DX>      ; *
  1099.                MOV   AX,[SI].infb.tpista1
  1100.                MOV   BL,[SI].infb.mfrontera
  1101.                MOV   BH,0
  1102.                SHL   BX,1
  1103.                MUL   BX                ; DX:AX = tpista1 * frontera * 2
  1104.                XPOP  <CX, BX>          ; * CX:BX = offset en disco
  1105.                SUB   BX,AX
  1106.                SBB   CX,DX
  1107.                MOV   [SI].cilindro,0   ; primera parte del disco
  1108.                JC    rwv_cil_ok
  1109.                MOV   AL,[SI].infb.mfrontera
  1110.                MOV   [SI].cilindro,AL  ; segunda parte del disco
  1111.                JMP   rwv_off_ok
  1112. rwv_cil_ok:    ADD   BX,AX
  1113.                ADC   CX,DX             ; restaurar offset
  1114. rwv_off_ok:    MOV   DX,CX
  1115.                CALL  tpistaAX
  1116.                XCHG  AX,BX             ; offset en DX:AX, BX = tpista
  1117.                POP   CX                ; *
  1118.                SHL   BX,1              ; BX = tpista * 2
  1119.                DIV   BX
  1120.                ADD   [SI].cilindro,AL  ; cilindro inicial
  1121.                MOV   AX,DX
  1122.                XOR   DX,DX             ; DX:AX = resto división
  1123.                SHR   BX,1
  1124.                DIV   BX
  1125.                MOV   [SI].cabezal,AL   ; cabezal inicial
  1126.                MOV   off_ini,DX        ; offset inicial
  1127.                MOV   AX,[SI].bytes_sector
  1128.                MUL   CX
  1129.                MOV   bytes,AX          ; bytes a transferir
  1130.                MOV   CX,3              ; reintentos en caso de error
  1131. trans_mas:     CMP   bytes,0
  1132.                JE    fin_trans
  1133.                PUSH  CX
  1134.                CALL  tpistaAX
  1135.                SUB   AX,off_ini        ; AX = bytes hasta final pista
  1136.                CMP   AX,bytes
  1137.                JB    ttrans_prep       ; ocupa la pista hasta el final
  1138.                MOV   AX,bytes
  1139. ttrans_prep:   ADD   AX,off_ini
  1140.                MOV   off_fin,AX
  1141.                CALL  haz_io
  1142.                POP   CX
  1143.                JNC   ttrans_ok
  1144.                CMP   status,3          ; error grave (prot. escrit.)
  1145.                JE    err_trans
  1146.                TEST  status,80h
  1147.                JNZ   err_trans         ; error grave (no preparada)
  1148.                CALL  reset_drv
  1149.                LOOP  trans_mas
  1150.                JMP   err_trans         ; fin de reintentos
  1151. ttrans_ok:     INC   [SI].cabezal
  1152.                CMP   [SI].cabezal,2
  1153.                JB    incs_ok
  1154.                MOV   [SI].cabezal,0
  1155.                INC   [SI].cilindro
  1156. incs_ok:       MOV   AX,off_fin
  1157.                SUB   AX,off_ini
  1158.                MOV   off_ini,0
  1159.                SUB   bytes,AX
  1160.                JMP   trans_mas
  1161. err_trans:     CLC
  1162.                CALL  motor_off_cnt     ; cuenta detención motor
  1163.                LDS   BX,pcab_peticion
  1164.                MOV   [BX].transfer_sect,0  ; movidos 0 sectores
  1165.                MOV   AH,CS:status
  1166.                CALL  errbios2dos
  1167.                RET
  1168. fin_trans:     CLC
  1169.                CALL  motor_off_cnt     ; cuenta detención motor
  1170.                MOV   AX,100h
  1171.                RET
  1172. rwv2mgui       ENDP
  1173.  
  1174.                ; --- Transferir desde off_ini a off_fin
  1175.  
  1176. haz_io         PROC
  1177.                CALL  direcc_ems        ; direccionar memoria EMS
  1178.                JNC   dirb_ok
  1179.                JMP   ret_io            ; fallo
  1180. dirb_ok:       CMP   orden,BIOS_READ
  1181.                JNE   escribir
  1182.                CALL  leida?
  1183.                JNC   upd_ok
  1184.                RET                     ; fallo en el flush
  1185. upd_ok:        JZ    ahorra_lect       ; pista ya leída
  1186.                CALL  motor_ok
  1187.                CALL  seek_drv
  1188.                CALL  lee_pista
  1189.                CALL  anotar_acceso
  1190.                JNC   ahorra_lect
  1191.                RET                     ; fallo al leer
  1192. ahorra_lect:   MOV   CX,off_fin
  1193.                SUB   CX,off_ini
  1194.                XPUSH <DS, SI>
  1195.                MOV   SI,off_ini
  1196.                MOV   DS,sbuffer
  1197.                CLD
  1198.                REP   MOVSB
  1199.                XPOP  <SI, DS>
  1200.                CLC
  1201.                JMP   ret_io
  1202. escribir:      CALL  leida?
  1203.                JC    ret_io            ; fallo en el flush
  1204.                MOV   CX,off_fin
  1205.                SUB   CX,off_ini
  1206.                CALL  tpistaAX
  1207.                CMP   CX,AX
  1208.                JE    escr_fast         ; escribir pista completa
  1209.                CALL  leida?
  1210.                JZ    escr_fast         ; pista ya en el buffer
  1211.                CALL  motor_ok
  1212.                CALL  seek_drv
  1213.                CALL  lee_pista         ; parcial: prelectura
  1214.                CALL  anotar_acceso
  1215.                JC    ret_io
  1216. escr_fast:     XPUSH <ES, DI>          ; *
  1217.                XPUSH <DS, SI>          ; **
  1218.                XPUSH <ES, DI>
  1219.                XPOP  <SI, DS>
  1220.                MOV   DI,CS:off_ini
  1221.                MOV   ES,CS:sbuffer
  1222.                PUSH  CX
  1223.                CLD
  1224.                REP   MOVSB
  1225.                POP   CX
  1226.                XPOP  <SI, DS>          ; **
  1227.                PUSH  AX                ; **
  1228.                MOV   AL,[SI].cilindro
  1229.                OR    AL,[SI].cabezal
  1230.                JNZ   escr
  1231.                XPUSH <SI, CX>          ; ***
  1232.                LEA   SI,[SI].infb
  1233.                MOV   DI,PINFOBOOT
  1234.                MOV   CX,TYPE InfoBoot
  1235.                CLD
  1236.                REP   MOVSB             ; palabras de sólo lectura :-)
  1237.                XPOP  <CX, SI>          ; ***
  1238. escr:          POP   AX                ; **
  1239.                XPOP  <DI, ES>          ; *
  1240.                CALL  escribir_pista    ; "escribir" pista en disco
  1241.                CALL  anotar_acceso
  1242.                JC    ret_io
  1243.                ADD   DI,CX             ; actualizar offset
  1244.                CLC
  1245. ret_io:        RET
  1246. haz_io         ENDP
  1247.  
  1248.                ; --- Mapear memoria EMS si es utilizada.
  1249.  
  1250. direcc_ems     PROC
  1251.                PUSH  SI
  1252.                CMP   ems_handle,0
  1253.                JE    seg_io_ok         ; no usada EMS
  1254.                MOV   AX,DI
  1255.                MOV   CL,4
  1256.                SHR   AX,CL
  1257.                MOV   CX,ES
  1258.                ADD   AX,CX             ; AX = dirección lineal ES:DI
  1259.                MOV   CX,marco_ems
  1260.                ADD   CX,1024           ; CX = base página 1
  1261.                MOV   BL,2              ; intentar usar página 2
  1262.                MOV   DX,2048           ; offset de la página física 2
  1263.                CMP   AX,CX
  1264.                JB    map_pag
  1265.                XOR   BL,BL             ; usar la 0 para no colisionar
  1266.                MOV   DX,0              ; offset de la página física 0
  1267. map_pag:       ADD   DX,marco_ems
  1268.                MOV   sbuffer,DX
  1269. rmap_pag:      MOV   DX,ems_handle
  1270.                MOV   AL,BL             ; página física
  1271.                MOV   AH,44h
  1272.                MOV   BX,0              ; primera página lógica
  1273.                PUSH  AX
  1274.                INT   67h               ; mapear página
  1275.                POP   BX
  1276.                CMP   AH,82h
  1277.                JE    rmap_pag          ; reintentar
  1278.                AND   AH,AH
  1279.                JNZ   seg_io_ko
  1280.                CMP   tbuffer,16384
  1281.                JBE   seg_io_ok         ; buffer de hasta 16K
  1282.                INC   BL                ; siguiente página física
  1283. rmap2:         MOV   AL,BL
  1284.                MOV   AH,44h
  1285.                MOV   BX,1              ; segunda página lógica
  1286.                MOV   DX,ems_handle
  1287.                PUSH  AX
  1288.                INT   67h               ; mapear página
  1289.                POP   BX
  1290.                CMP   AH,82h
  1291.                JE    rmap2             ; reintentar
  1292.                AND   AH,AH
  1293.                JNZ   seg_io_ko
  1294. seg_io_ok:     CLC                     ; Ok
  1295.                POP   SI
  1296.                RET
  1297. seg_io_ko:     MOV   status,20h
  1298.                STC                     ; fallo
  1299.                POP   SI
  1300.                RET
  1301. direcc_ems     ENDP
  1302.  
  1303.                ; --- Vaciar buffer a disco. Si se trabaja con EMS,
  1304.                ;     previamente se mapea la memoria.
  1305.  
  1306. abs_flush      PROC
  1307.                CLI
  1308.                CMP   wrpend,ON
  1309.                JE    _abs_flush
  1310.                STI
  1311.                CLC
  1312.                RET
  1313. _abs_flush:    MOV   wrpend,OFF
  1314.                STI
  1315.                CMP   ems_handle,0
  1316.                JNE   flush_ems
  1317.                JMP   _flush_cache      ; no usada memoria EMS
  1318. flush_ems:     MOV   DX,ems_handle     ; usada memoria EMS
  1319.                MOV   AH,47h
  1320.                INT   67h               ; preservar el contexto
  1321.                CMP   AH,82h            
  1322.                JE    flush_ems         ; reintentar
  1323.                AND   AH,AH
  1324.                JNZ   absf_ret
  1325.                CALL  direcc_ems
  1326.                CALL  _flush_cache
  1327.                PUSH  AX
  1328. rrst2:         MOV   DX,ems_handle
  1329.                MOV   AH,48h
  1330.                INT   67h               ; restaurar el contexto
  1331.                CMP   AH,82h
  1332.                JE    rrst2             ; reintentar
  1333.                POP   AX
  1334. absf_ret:      RET
  1335. abs_flush      ENDP
  1336.  
  1337.                ; --- Vaciar buffer a disco. La escritura efectiva se
  1338.                ;     retarda para reducir accesos redundantes.
  1339.  
  1340. flush_cache    PROC
  1341.                CLI
  1342.                CMP   wrpend,ON
  1343.                JE    _flush_cache
  1344.                STI
  1345.                CLC
  1346.                RET
  1347. _flush_cache:  MOV   wrpend,OFF
  1348.                STI
  1349.                PUSH  SI
  1350.                LEA   SI,info_BUF
  1351.                CMP   [SI].unidad,-1
  1352.                JE    fc_ret
  1353.                CALL  motor_ok
  1354.                CALL  seek_drv
  1355.                CALL  escribe_pista
  1356.                CALL  anotar_acceso
  1357. fc_ret:        POP   SI
  1358.                RET
  1359. flush_cache    ENDP
  1360.  
  1361.                ; --- Simular escritura en disco, aunque realmente se
  1362.                ;     hará normalmente más tarde ("delayed write") a
  1363.                ;     menos que esté activa la verificación.
  1364.  
  1365. escribir_pista PROC
  1366.                CMP   [SI].prot_esc,ON
  1367.                JNE   wr_posible
  1368.                MOV   status,3             ; protegida de escritura
  1369.                STC
  1370.                RET
  1371. wr_posible:    CMP   verificar,ON
  1372.                JE    wr_fisico            ; verificación activa...
  1373.                CMP   cachewr,ON
  1374.                JE    delayed_wr
  1375. wr_fisico:     CALL  motor_ok             ; caché desactivada
  1376.                CALL  seek_drv
  1377.                CALL  escribe_pista
  1378.                JC    wr_fs_ret
  1379.                CMP   verificar,OFF
  1380.                JE    wr_fs_ret            ; CF=0
  1381.                CALL  lee_pista            ; detectar posible fallo
  1382. wr_fs_ret:     RET
  1383. delayed_wr:    MOV   expiraw,W_CACHE_TM   ; recargar contador de
  1384.                MOV   wrpend,ON            ; tiempo para escritura
  1385.                CLC                        ; retardada
  1386.                RET
  1387. escribir_pista ENDP
  1388.  
  1389. ; ------------ Comprobar si la pista está en el buffer. En caso de
  1390. ;              estarlo se retorna con ZF=1. Si no estaba aún, se
  1391. ;              vacía el contenido del buffer (si aún no estaba
  1392. ;              escrito en disco) en previsión de una futura
  1393. ;              lectura, retornando con ZF=0 (ó CF=1 si hay error
  1394. ;              al escribir).
  1395.  
  1396. leida?         PROC
  1397.                PUSH  AX
  1398.                MOV   AL,info_BUF.unidad
  1399.                CMP   AL,[SI].unidad
  1400.                JNE   no_leida          ; es en otra unidad
  1401.                MOV   AL,[SI].cilindro
  1402.                CMP   AL,info_BUF.cilindro
  1403.                JNE   no_leida
  1404.                MOV   AH,[SI].cabezal
  1405.                CMP   AH,info_BUF.cabezal
  1406.                JNE   no_leida          ; es en otro cilindro/cabezal
  1407.                POP   AX
  1408.                RET                     ; está en el buffer CF=0, ZF=1
  1409. no_leida:      CALL  flush_cache
  1410.                JC    ret_leida?        ; CF = 1 si error en el flush
  1411.                CMP   SP,0
  1412.                CLC                     ; CF = ZF = 0
  1413. ret_leida?:    POP   AX
  1414.                RET                     ; pista no leída
  1415. leida?         ENDP
  1416.  
  1417.                ; --- Tomar nota de la pista que ocupa el buffer para
  1418.                ;     evitar accesos a disco redundantes. A la entrada,
  1419.                ;     CF=1 señala error e invalida el buffer. Se anotan
  1420.                ;     también los demás parámetros, necesarios para una
  1421.                ;     posible escritura desde la interrupción periódica.
  1422.  
  1423. anotar_acceso  PROC
  1424.                MOV   info_BUF.unidad,-1   ; invalidar buffer si error
  1425.                JC    anotado
  1426.                XPUSH <CX, SI, DI, ES>
  1427.                PUSH  DS
  1428.                POP   ES
  1429.                LEA   DI,info_BUF
  1430.                MOV   CX,TYPE info_unidad
  1431.                CLD
  1432.                REP   MOVSB
  1433.                XPOP  <ES, DI, SI, CX>
  1434.                CLC
  1435. anotado:       RET
  1436. anotar_acceso  ENDP
  1437.  
  1438. ; ------------ Devolver el tamaño de la pista según la posición
  1439. ;              del cabezal (necesario en discos /DH).
  1440.  
  1441. tpistaAX       PROC
  1442.                MOV   AL,CS:[SI].infb.mfrontera
  1443.                CMP   CS:[SI].cilindro,AL
  1444.                MOV   AX,CS:[SI].infb.tpista1
  1445.                JB    tpis_ax
  1446.                MOV   AX,CS:[SI].infb.tpista2
  1447. tpis_ax:       RET
  1448. tpistaAX       ENDP
  1449.  
  1450. ; ------------ Asegurar que el motor está en marcha.
  1451.  
  1452. motor_ok       PROC
  1453.                XPUSHA                  ; *
  1454.                PUSH  DS                ; **
  1455.                MOV   BX,40h
  1456.                PUSH  BX
  1457.                POP   DS
  1458.                MOV   CH,255-18         ; CH = 255 - 1 segundo
  1459.                CLI
  1460.                MOV   CL,CS:[SI].unidad
  1461.                MOV   AL,1
  1462.                SHL   AL,CL
  1463.                TEST  [BX-1],AL         ; ¿motor en marcha?
  1464.                JZ    arrancarlo        ; arrancarlo
  1465.                CMP   [BX],CH           ; Si encendido y acelerado...
  1466.                JBE   ok_motor          ; ...seguir
  1467. arrancarlo:    MOV   AH,CL
  1468.                MOV   CL,4
  1469.                SHL   AH,CL             ; unidad << 4
  1470.                OR    AL,AH
  1471.                MOV   [BX-1],AL         ; nuevo estado motores
  1472.                MOV   BYTE PTR [BX],255 ; asegurar que no se pare
  1473.                MOV   DX,FD_DOR         ; registro de salida digital
  1474.                ADD   CL,CS:[SI].unidad
  1475.                MOV   AL,1
  1476.                SHL   AL,CL             ; colocar bit del motor
  1477.                OR    AL,CS:[SI].unidad ; seleccionar unidad
  1478.                OR    AL,00001100b      ; modo DMA, no hacer reset
  1479.                OUT   DX,AL             ; poner en marcha el motor
  1480.                STI
  1481.                MOV   AX,90FDh
  1482.                CLC
  1483.                INT   15h               ; permitir multitarea
  1484.                JC    ok_motor          ; timeout
  1485.                MOV   AX,1000           ; 1 segundo aceleración
  1486.                CALL  retardo           ; esperar aceleración disco
  1487. ok_motor:      MOV   [BX],CH           ; cuenta máxima detención motor
  1488.                STI                     ; sin forzar futura aceleración
  1489.                POP   DS                ; **
  1490.                XPOPA                   ; *
  1491.                RET
  1492. motor_ok       ENDP
  1493.  
  1494. ; ------------ Establecer modalidad de operación del controlador
  1495. ;              y poner el motor en marcha. Si CF=1 se le da tiempo
  1496. ;              además a la unidad para que acelere.
  1497.  
  1498. reset_drv      PROC
  1499.                XPUSHA
  1500.                CALL  motor_off_cnt     ; cuenta detención motor
  1501.                STC
  1502.                CALL  set_rate          ; velocidad correcta
  1503.                MOV   CL,[SI].unidad
  1504.                MOV   AL,CL             ; unidad seleccionada
  1505.                SHL   AL,1
  1506.                SHL   AL,1
  1507.                SHL   AL,1
  1508.                SHL   AL,1
  1509.                MOV   AH,1              ; bit de motor
  1510.                SHL   AH,CL             ; colocar dicho bit
  1511.                OR    AL,AH
  1512.                PUSH  DS                ; *
  1513.                DDS
  1514.                CLI
  1515.                MOV   DS:[3Fh],AL
  1516.                AND   BYTE PTR DS:[3Eh],70h ; bit IRQ=0 y recalibrar
  1517.                POP   DS                ; *
  1518.                SHL   AL,1
  1519.                SHL   AL,1
  1520.                SHL   AL,1
  1521.                SHL   AL,1              ; bits motor en nibble alto
  1522.                OR    AL,CL             ; seleccionar unidad
  1523.                OR    AL,00001000b      ; interrupciones+DMA y reset
  1524.                MOV   DX,FD_DOR         ; registro de salida digital
  1525.                OUT   DX,AL             ; señal de reset
  1526.                CALL  fdc_respiro       ; tiempo reconocer reset en 486
  1527.                OR    AL,00000100b
  1528.                OUT   DX,AL             ; fin de señal de reset
  1529.                CALL  reset_DMA
  1530.                CALL  reset_irq
  1531.                CALL  espera_int        ; rehabilitará interrupciones
  1532.                AND   status,7Fh        ; perdonar controladora rara
  1533.                MOV   AL,8
  1534.                CALL  fdc_write         ; comando 'leer estado int...'
  1535.                CALL  fdc_read
  1536.                CALL  fdc_read
  1537.                STC
  1538.                CALL  envia_specify     ; comando 'specify' adecuado
  1539.                XPOPA
  1540.                RET
  1541. reset_drv      ENDP
  1542.  
  1543. ; ------------ Reset "blando" para que el FDC deje de enviar/recibir.
  1544.  
  1545. reset_fast     PROC
  1546.                XPUSHA
  1547.                MOV   CL,[SI].unidad
  1548.                ADD   CL,4
  1549.                MOV   AL,1
  1550.                SHL   AL,CL             ; bits motor en nibble alto
  1551.                OR    AL,[SI].unidad    ; seleccionar unidad
  1552.                OR    AL,00001000b      ; interrupciones+DMA y reset
  1553.                MOV   DX,FD_DOR         ; registro de salida digital
  1554.                CLI
  1555.                OUT   DX,AL             ; señal de reset
  1556.                CALL  fdc_respiro       ; tiempo reconocer reset en 486
  1557.                OR    AL,00000100b
  1558.                OUT   DX,AL             ; fin de señal de reset
  1559.                CALL  reset_DMA
  1560.                CALL  reset_irq
  1561.                CALL  espera_int        ; rehabilitará interrupciones
  1562.                AND   status,7Fh        ; perdonar controladora rara
  1563.                MOV   AL,8
  1564.                CALL  fdc_write         ; comando 'leer estado int...'
  1565.                CALL  fdc_read
  1566.                CALL  fdc_read
  1567.                STC
  1568.                CALL  envia_specify     ; comando 'specify' con DMA
  1569.                XPOPA
  1570.                RET
  1571. reset_fast     ENDP
  1572.  
  1573. ; ------------ Desactivar el modo DMA si procede (antes de leer o
  1574. ;              escribir). Además de enviar al FDC el comando specify
  1575. ;              adecuado, se selecciona el modo no-DMA (si fuera
  1576. ;              preciso) en el registro de salida digital (necesario en
  1577. ;              algunas controladoras).
  1578.  
  1579. dma_si_o_no    PROC
  1580.                CMP   modoDMA,ON
  1581.                JE    dmsnret
  1582.                XPUSHA
  1583.                MOV   CL,[SI].unidad
  1584.                ADD   CL,4
  1585.                MOV   AL,1
  1586.                SHL   AL,CL             ; bits motor en nibble alto
  1587.                OR    AL,[SI].unidad    ; seleccionar unidad
  1588.                OR    AL,00000100b      ; modo no-DMA, sin reset
  1589.                MOV   DX,FD_DOR
  1590.                OUT   DX,AL
  1591.                CLC
  1592.                CALL  envia_specify     ; comando 'specify' adecuado
  1593.                XPOPA
  1594. dmsnret:       RET
  1595. dma_si_o_no    ENDP
  1596.  
  1597. ; ------------ Inhibir y borrar petición en el canal 2 de DMA. No es
  1598. ;              realmente necesario, porque la controladora ya no
  1599. ;              transmite más después del reset, es sólo por seguridad.
  1600.  
  1601. reset_DMA      PROC
  1602.                PUSH  AX
  1603.                MOV   AL,2
  1604.                DELAY
  1605.                OUT   09h,AL            ; borrar petición por software
  1606.                MOV   AL,6
  1607.                DELAY
  1608.                OUT   0Ah,AL            ; inhibir canal 2
  1609.                POP   AX
  1610.                RET
  1611. reset_DMA      ENDP
  1612.  
  1613. ; ------------ Borrar bit de interrupción pendiente para asegurar
  1614. ;              su correcta detección si llegó antes alguna inesperada,
  1615. ;              aunque realmente no tiene por qué suceder.
  1616.  
  1617. reset_irq      PROC
  1618.                PUSHF
  1619.                PUSH  DS
  1620.                DDS
  1621.                AND   BYTE PTR DS:[3Eh],7Fh  ; asegurar detección int.
  1622.                POP   DS
  1623.                POPF
  1624.                RET
  1625. reset_irq      ENDP
  1626.  
  1627. ; ------------ Enviar comando specify a la controladora. El step-rate
  1628. ;              se selecciona según la densidad, para evitar un sonido
  1629. ;              extraño al posicionar o recalibrar el cabezal. A la
  1630. ;              entrada, CF=1 selecciona modo DMA y 0 no-DMA
  1631.  
  1632. envia_specify  PROC
  1633.                PUSH  AX                ; *
  1634.                PUSHF                   ; **
  1635.                PUSH  DS
  1636.                DDS
  1637.                MOV   AH,DS:[8Bh]
  1638.                POP   DS
  1639.                MOV   AL,3              ; comando 'specify'
  1640.                CALL  fdc_write
  1641.                MOV   AL,0BFh           ; step rate para 500 kbps
  1642.                AND   AH,11000000b
  1643.                JZ    spec1_ok
  1644.                MOV   AL,0AFh           ; step rate para 1 Mbps
  1645.                CMP   AH,11000000b
  1646.                JE    spec1_ok
  1647.                MOV   AL,0DFh           ; step rate para 250/300 Kbps
  1648. spec1_ok:      CALL  fdc_write
  1649.                MOV   AL,2              ; modo DMA
  1650.                POPF                    ; **
  1651.                JC    spec2_ok
  1652.                MOV   AL,3              ; modo no DMA
  1653. spec2_ok:      CALL  fdc_write
  1654.                POP   AX                ; *
  1655.                RET
  1656. envia_specify  ENDP
  1657.  
  1658. ; ------------ Recargar cuenta para la detención del motor. Si CF=1 al
  1659. ;              entrar, se establece la mayor cuenta posible; en caso
  1660. ;              contrario, se pone el valor normal de la tabla base.
  1661.  
  1662. motor_off_cnt  PROC
  1663.                XPUSHA
  1664.                PUSH  DS
  1665.                MOV   AL,0FFh           ; valor máximo
  1666.                JC    motor_off_ok
  1667.                XOR   BX,BX
  1668.                MOV   DS,BX
  1669.                LDS   BX,DWORD PTR DS:[1Eh*4] ; DS:BX -> INT 1Eh
  1670.                MOV   AL,[BX+2]               ; byte 2 tabla base disco
  1671. motor_off_ok:  DDS
  1672.                MOV   BYTE PTR DS:[40h],AL  ; cuenta parada motor
  1673.                POP   DS
  1674.                XPOPA
  1675.                RET
  1676. motor_off_cnt  ENDP
  1677.  
  1678. ; ------------ Llevar el cabezal a la pista indicada, recalibrando si
  1679. ;              hubo un reset (se invocó la función 0 de la INT 13h o
  1680. ;              se ejecutó reset_drv) antes de esta operación. Primero
  1681. ;              se selecciona la velocidad de transferencia y se borra
  1682. ;              el resultado de cualquier operación anterior, para que
  1683. ;              todo quede listo para el próximo acceso a disco.
  1684.  
  1685. seek_drv       PROC
  1686.                XPUSHA
  1687.                CLC
  1688.                CALL  set_rate          ; velocidad / borrar resultados
  1689.                STC
  1690.                CALL  envia_specify     ; comando 'specify' adecuado
  1691.                MOV   AH,1
  1692.                MOV   CL,[SI].unidad
  1693.                SHL   AH,CL             ; AH = 1 (A:) ó 2 (B:)
  1694.                PUSH  DS
  1695.                DDS
  1696.                TEST  AH,DS:[3Eh]
  1697.                POP   DS
  1698.                JNZ   do_seek           ; la unidad ya fue recalibrada
  1699.                CALL  recalibrar
  1700.                JC    fallo_seek        ; fallo al recalibrar
  1701. do_seek:       CMP   [SI].cilindro,0
  1702.                JNE   seek_deveras
  1703.                CALL  recalibrar        ; ir a la pista 0
  1704.                JMP   seek_ok
  1705. seek_deveras:  MOV   BX,94h
  1706.                ADD   BL,[SI].unidad
  1707.                MOV   AL,[SI].cilindro
  1708.                PUSH  DS                ; *
  1709.                DDS
  1710.                MOV   CH,[BX]           ; cilindro previo
  1711.                MOV   [BX],AL           ; nuevo cilindro
  1712.                POP   DS                ; *
  1713.                CMP   AL,CH
  1714.                JE    seek_ret          ; seek innecesario
  1715. hacer_seek:    SUB   AL,CH
  1716.                JC    seek_neg          ; seek hacia atrás
  1717. seek_pos:      CALL  seek_fisico       ; seek hacia delante
  1718.                JC    fallo_seek
  1719.                JMP   seek_ok
  1720. seek_neg:      ADD   AL,CH
  1721.                CALL  recalibrar        ; ir a la pista 0
  1722.                MOV   [SI].cilindro,AL
  1723.                JC    fallo_seek
  1724.                JMP   seek_deveras      ; y luego a donde sea
  1725. seek_ok:       MOV   AX,15             ; 15 milisegundos
  1726.                CALL  retardo           ; esperar asentamiento cabezal
  1727. seek_ret:      CLC                     ; retornar con éxito
  1728. ret_seek:      XPOPA
  1729.                RET
  1730. fallo_seek:    XPOPA
  1731.                STC                     ; retornar indicando fallo
  1732.                RET
  1733.  
  1734.                ; --- Como el registro interno de la controladora se
  1735.                ;     pone a 0 tras el reset, el seek es por importe
  1736.                ;     de la diferencia entre el cilindro origen y el
  1737.                ;     destino (para retroceder se recalibra antes).
  1738.  
  1739. seek_fisico:   MOV   CH,AL             ; magnitud del "salto"
  1740.                MOV   AL,0Fh
  1741.                CALL  fdc_write         ; comando 'seek'
  1742.                JC    sk_fs_nok
  1743.                MOV   AL,[SI].cabezal
  1744.                SHL   AL,1
  1745.                SHL   AL,1
  1746.                OR    AL,[SI].unidad
  1747.                CALL  fdc_write         ; enviar HD, US1, US0
  1748.                MOV   AL,CH             ; cilindro aparente
  1749.                CALL  reset_irq
  1750.                CALL  fdc_write         ; enviar cilindro
  1751.                CALL  espera_int        ; esperar interrupción
  1752.                JC    sk_fs_nok
  1753.                MOV   AL,8
  1754.                CALL  fdc_write         ; comando 'leer estado int...'
  1755.                JC    sk_fs_nok
  1756.                CALL  fdc_read          ; leer registro de estado 0
  1757.                JC    sk_fs_nok
  1758.                MOV   AH,AL
  1759.                CALL  fdc_read          ; leer cilindro actual
  1760.                TEST  AH,11000000b      ; comprobar ST0
  1761.                JNZ   sk_fs_nok
  1762. sk_fs_ok:      CLC
  1763.                RET
  1764. sk_fs_nok:     STC
  1765.                RET
  1766. seek_drv       ENDP
  1767.  
  1768. ; ------------ Establecer velocidad de transferencia correcta si aún
  1769. ;              no ha sido seleccionada y borrar el resultado de otra
  1770. ;              operación previa.  Si CF=1 al entrar, la velocidad se
  1771. ;              establece  incondicionalmente  (por si la variable de
  1772. ;              la BIOS no está correctamente asignada).
  1773.  
  1774. set_rate       PROC
  1775.                XPUSHA
  1776.                PUSHF
  1777.                MOV   AL,[SI].infb.mfrontera
  1778.                CMP   [SI].cilindro,AL
  1779.                MOV   AL,[SI].vunidad1       ; velocidad primera parte
  1780.                MOV   AH,[SI].infb.vunidad2  ; velocidad segunda parte
  1781.                JB    vel_ok
  1782.                MOV   AL,AH
  1783. vel_ok:        POPF
  1784.                PUSH  DS                ; *
  1785.                DDS
  1786.                JC    abs_rate
  1787.                MOV   AH,DS:[8Bh]
  1788.                MOV   CL,6
  1789.                SHR   AH,CL             ; aislar bits de velocidad
  1790.                CMP   AL,AH
  1791.                JE    vel_set           ; velocidad ya seleccionada
  1792. abs_rate:      MOV   DX,FD_DCR
  1793.                OUT   DX,AL             ; seleccionarla
  1794.                MOV   CL,6
  1795.                SHL   AL,CL
  1796.                AND   BYTE PTR DS:[8Bh],00111111b
  1797.                OR    DS:[8Bh],AL
  1798. vel_set:       POP   DS                ; *
  1799.                LEA   DI,status
  1800.                MOV   CX,8
  1801. borra_status:  MOV   [DI],CH           ; borrar información de estado
  1802.                INC   DI
  1803.                LOOP  borra_status
  1804.                XPOPA
  1805.                RET
  1806. set_rate       ENDP
  1807.  
  1808. ; ------------ Recalibrar la unidad (si hay error se intenta otra vez
  1809. ;              para el caso de que deba moverse más de 77 pistas).
  1810.  
  1811. recalibrar     PROC
  1812.                XPUSHA
  1813.                MOV   BX,94h
  1814.                ADD   BL,[SI].unidad
  1815.                PUSH  DS                ; *
  1816.                DDS
  1817.                MOV   [BX],BH           ; pista actual = 0
  1818.                POP   DS                ; *
  1819.                MOV   CX,2              ; dos veces como mucho
  1820. recalibra:     MOV   AL,7
  1821.                CALL  fdc_write         ; comando de 'recalibrado'
  1822.                JC    fallo_recal
  1823.                MOV   AL,[SI].cabezal
  1824.                SHL   AL,1
  1825.                SHL   AL,1
  1826.                OR    AL,[SI].unidad
  1827.                CALL  reset_irq
  1828.                CALL  fdc_write         ; enviar HD, US1, US0
  1829.                JC    fallo_recal
  1830.                CALL  espera_int        ; esperar interrupción
  1831.                JC    fallo_recal
  1832.                MOV   AL,8
  1833.                CALL  fdc_write         ; comando 'leer estado int...'
  1834.                JC    fallo_recal
  1835.                CALL  fdc_read          ; leer registro de estado 0
  1836.                JC    fallo_recal
  1837.                MOV   AH,AL
  1838.                CALL  fdc_read          ; leer cilindro actual
  1839.                XOR   AH,00100000b      ; bajar bit de 'seek end'
  1840.                TEST  AH,11110000b      ; comprobar resultado y ST0
  1841.                JNZ   fallo_recal       ; sin 'seek end' o TRK0
  1842.                MOV   AX,1              ; pausa de 1 ms
  1843.                CALL  retardo
  1844.                JMP   recal_ret
  1845. fallo_recal:   CALL  reset_fast
  1846.                LOOP  recalibra         ; reintentar comando
  1847.                STC                     ; condición de fallo
  1848.                XPOPA
  1849.                RET
  1850. recal_ret:     MOV   AH,1
  1851.                MOV   CL,[SI].unidad
  1852.                SHL   AH,CL             ; AH = 1 (A:) ó 2 (B:)
  1853.                MOV   BX,94h
  1854.                ADD   BL,CL
  1855.                PUSH  DS
  1856.                DDS
  1857.                OR    DS:[3Eh],AH       ; unidad ya recalibrada
  1858.                POP   DS
  1859.                CLC
  1860.                XPOPA
  1861.                RET
  1862. recalibrar     ENDP
  1863.  
  1864. ; ------------ Escribir pista. En modo test (gaprw == -1) se escriben
  1865. ;              sólo los bytes de la pista (sin almacenar el checksum
  1866. ;              ni el GAP anti-FIFO).
  1867.  
  1868. escribe_pista  PROC
  1869.                XPUSHA
  1870.                CALL  dma_si_o_no       ; modo no-DMA si es preciso
  1871.                PUSH  ES                ; *
  1872.                MOV   ES,sbuffer
  1873.                CALL  tpistaAX
  1874.                MOV   CX,AX
  1875.                XOR   BX,BX
  1876.                XOR   AX,AX
  1877.                MOV   DX,2
  1878.                SHR   CX,1
  1879.                PUSHF
  1880. calc_chk:      ADD   AX,ES:[BX]        ; calcular checksum en AX
  1881.                ADD   BX,DX
  1882.                LOOP  calc_chk
  1883.                POPF
  1884.                JNC   fcalc_chk
  1885.                ADD   AL,ES:[BX]        ; nº de bytes impar
  1886.                ADC   AH,0
  1887.                INC   BX
  1888. fcalc_chk:     MOV   CX,gaprw
  1889.                CMP   CX,-1
  1890.                JE    wfis1
  1891.                NOT   AX
  1892.                MOV   ES:[BX],AX        ; NOT (checksum)
  1893.                JCXZ  wfis1
  1894.                MOV   AL,0
  1895. gapw:          MOV   ES:[BX+2],AL      ; "GAP"
  1896.                INC   BX
  1897.                LOOP  gapw
  1898. wfis1:         POP   ES                ; *
  1899.                CALL  tpistaAX
  1900.                CMP   gaprw,-1          ; ¿escritura de test?
  1901.                JE    wfis2
  1902.                ADD   AX,SYSBYTES
  1903.                ADD   AX,gaprw          ; bytes extra tras datos
  1904. wfis2:         MOV   CX,AX
  1905.                DEC   CX                ; bytes totales - 1
  1906.                MOV   AX,sbuffer
  1907.                XOR   DI,DI
  1908.                CALL  calc_dir_DMA      ; AX:DI -> base BX y página AH
  1909.                MOV   AL,F_WRITE        ; modo DMA necesario
  1910.                CALL  prepara_DMA
  1911.                MOV   AL,11000101b      ; comando de escritura del FDC
  1912.                CALL  fdc_write
  1913.                JC    escr_ko
  1914.                MOV   AL,[SI].cabezal
  1915.                SHL   AL,1
  1916.                SHL   AL,1
  1917.                OR    AL,[SI].unidad
  1918.                CALL  fdc_write         ; byte 1 de la orden
  1919.                MOV   AL,[SI].cilindro
  1920.                CALL  fdc_write         ; enviar cilindro
  1921.                MOV   AL,[SI].cabezal
  1922.                CALL  fdc_write         ; enviar cabezal
  1923.                MOV   AL,0
  1924.                CALL  fdc_write         ; enviar nº sector
  1925.                MOV   AL,[SI].tsector
  1926.                CALL  fdc_write         ; longitud sector
  1927.                MOV   AL,0
  1928.                CALL  fdc_write         ; último sector
  1929.                MOV   AL,8
  1930.                CALL  fdc_write         ; GAP no usado, pero...
  1931.                MOV   AL,128
  1932.                CLI                     ; ir inhibiéndolas ya
  1933.                CALL  fdc_write         ; tamaño sector si longitud=0
  1934.                CALL  espia_dma
  1935.                JMP   escr_ret
  1936. escr_ko:       STC                     ; indicar fallo
  1937. escr_ret:      XPOPA
  1938.                RET
  1939. escribe_pista  ENDP
  1940.  
  1941. ; ------------ Leer pista. En modo test (gaprw == -1) no se leen los
  1942. ;              bytes finales con el checksum (aunque sí se comparan al
  1943. ;              final: el error se debe desechar y comprobar el éxito
  1944. ;              de otra manera).
  1945.  
  1946. lee_pista      PROC
  1947.                XPUSHA
  1948.                CALL  dma_si_o_no       ; modo no-DMA si es preciso
  1949.                CALL  tpistaAX
  1950.                CMP   gaprw,-1
  1951.                JE    rfis              ; lectura de test
  1952.                ADD   AX,SYSBYTES
  1953.                ADD   AX,gaprw          ; bytes extra tras datos
  1954. rfis:          MOV   CX,AX
  1955.                DEC   CX                ; bytes totales - 1
  1956.                MOV   AX,sbuffer
  1957.                XOR   DI,DI
  1958.                CALL  calc_dir_DMA      ; AX:DI -> base BX y página AH
  1959.                MOV   AL,F_READ         ; modo DMA necesario
  1960.                CALL  prepara_DMA
  1961.                MOV   AL,11100110b      ; comando de lectura del FDC
  1962.                CALL  fdc_write
  1963.                MOV   DL,20h
  1964.                JC    leer_err
  1965.                MOV   AL,[SI].cabezal
  1966.                SHL   AL,1
  1967.                SHL   AL,1
  1968.                OR    AL,[SI].unidad
  1969.                CALL  fdc_write         ; byte 1 de la orden
  1970.                MOV   AL,[SI].cilindro
  1971.                CALL  fdc_write         ; enviar cilindro
  1972.                MOV   AL,[SI].cabezal
  1973.                CALL  fdc_write         ; enviar cabezal
  1974.                MOV   AL,0
  1975.                CALL  fdc_write         ; enviar nº sector
  1976.                MOV   AL,[SI].tsector
  1977.                CALL  fdc_write         ; longitud sector
  1978.                MOV   AL,0
  1979.                CALL  fdc_write         ; último sector
  1980.                MOV   AL,8
  1981.                CALL  fdc_write         ; GAP no usado, pero...
  1982.                MOV   AL,128
  1983.                CLI                     ; ir inhibiéndolas ya
  1984.                CALL  fdc_write         ; tamaño sector si longitud=0
  1985.                CALL  espia_dma
  1986.                JC    leer_ret          ; hubo error
  1987.                PUSH  ES                ; *
  1988.                MOV   ES,sbuffer
  1989.                CALL  tpistaAX
  1990.                MOV   CX,AX
  1991.                XOR   BX,BX
  1992.                XOR   AX,AX
  1993.                MOV   DX,2
  1994.                SHR   CX,1
  1995.                PUSHF
  1996. test_chk:      ADD   AX,ES:[BX]        ; calcular checksum en AX
  1997.                ADD   BX,DX
  1998.                LOOP  test_chk
  1999.                POPF
  2000.                JNC   ftest_chk
  2001.                ADD   AL,ES:[BX]        ; nº de bytes impar
  2002.                ADC   AH,0
  2003.                INC   BX
  2004. ftest_chk:     NOT   AX                ; NOT (checksum)
  2005.                MOV   CX,ES:[BX]        ; checksum en disco en CX
  2006.                POP   ES                ; *
  2007.                MOV   DL,10h            ; 'error de CRC'
  2008.                CMP   AX,CX
  2009.                JNE   leer_err
  2010.                CLC                     ; Ok
  2011.                JMP   leer_ret
  2012. leer_err:      OR    status,DL
  2013.                STC                     ; indicar fallo
  2014. leer_ret:      XPOPA
  2015.                RET
  2016. lee_pista      ENDP
  2017.  
  2018. ; ------------ Cuando el DMA acabe... resetear controladora. A la
  2019. ;              entrada, las interrupciones deben estar inhibidas.
  2020. ;              Si no se emplea el DMA ... se resetea cuando se han
  2021. ;              enviado/recibido directamente los bytes necesarios.
  2022. ;              Se reprograma el 8254 para asegurar a ultranza que
  2023. ;              produce las 18,2 irqs/seg habituales y para contar
  2024. ;              exactamente el tiempo que pasará en esta rutina: la
  2025. ;              pérdida de exactitud que supone recargar la cuenta
  2026. ;              no se puede comparar ni remotamente a la de tener
  2027. ;              las interrupciones inhibidas ;-)
  2028.  
  2029. espia_dma      PROC
  2030.                XPUSH <ES, DI>          ; *
  2031.                MOV   ES,sbuffer
  2032.                MOV   AL,00010110b
  2033.                OUT   43h,AL            ; 8254: cnt0 byte bajo
  2034.                MOV   AL,0
  2035.                DELAY
  2036.                OUT   40h,AL            ; asegurar recarga = 0000h
  2037.                MOV   AL,00100110b
  2038.                DELAY
  2039.                OUT   43h,AL            ; 8254: cnt0 byte alto
  2040.                MOV   AL,0
  2041.                DELAY
  2042.                OUT   40h,AL            ; asegurar recarga = 0000h
  2043.                DELAY
  2044.                IN    AL,40h
  2045.                MOV   BL,AL             ; estado de la cuenta alta
  2046.                MOV   DX,FD_STATUS
  2047.                MOV   CX,TICSTIMEOUT    ; constante de timeout
  2048.                CMP   modoDMA,ON
  2049.                JE    wait_dma
  2050.                XOR   DI,DI             ; ES:DI -> sbuffer
  2051.                MOV   AH,BL
  2052.                MOV   BX,bytesIO
  2053.                CMP   sentidoIO,F_READ
  2054.                JE    rd_nodma
  2055.  
  2056. wr_nodma:      IN    AL,DX             ; transferencia sin DMA
  2057.                TEST  AL,10000000b
  2058.                JNZ   wr_byte
  2059.                IN    AL,40h
  2060.                CMP   AL,AH
  2061.                JE    wr_nodma          ; no han pasado 256/1193180 seg
  2062.                MOV   AH,AL
  2063.                LOOP  wr_nodma
  2064.                JMP   io_timeout
  2065. wr_byte:       TEST  AL,01000000b      ; ¿fdc->cpu en vez de cpu->fdc?
  2066.                JNZ   io_result         ; así es: fallo en escritura
  2067.                MOV   AL,ES:[DI]
  2068.                INC   DX                ; apuntar al registro de datos
  2069.                OUT   DX,AL             ; escribir byte de la pista
  2070.                DEC   DX
  2071.                INC   DI
  2072.                DEC   BX
  2073.                JNZ   wr_nodma          ; hasta acabar pista
  2074.                JMP   io_fin
  2075.  
  2076. rd_nodma:      IN    AL,DX             ; transferencia sin DMA
  2077.                TEST  AL,10000000b
  2078.                JNZ   rd_byte
  2079.                IN    AL,40h
  2080.                CMP   AL,AH
  2081.                JE    rd_nodma          ; no han pasado 256/1193180 seg
  2082.                MOV   AH,AL
  2083.                LOOP  rd_nodma
  2084.                JMP   io_timeout
  2085. rd_byte:       TEST  AL,00100000b      ; ¿fase de ejecución?
  2086.                JZ    io_result         ; no: fallo en lectura
  2087.                INC   DX                ; apuntar al registro de datos
  2088.                IN    AL,DX             ; leer byte de la pista
  2089.                DEC   DX
  2090.                STOSB
  2091.                DEC   BX
  2092.                JNZ   rd_nodma          ; hasta acabar pista
  2093.                JMP   io_fin
  2094.  
  2095. wait_dma:      IN    AL,DX             ; transferencia con DMA
  2096.                XOR   AL,11000000b
  2097.                TEST  AL,11000000b
  2098.                JZ    io_result         ; hay resultados del FDC
  2099.                IN    AL,5
  2100.                MOV   AH,AL
  2101.                IN    AL,5              ; contador del canal 2
  2102.                CMP   AX,-1
  2103.                JE    io_fin            ; fin de la cuenta del DMA
  2104.                IN    AL,40h
  2105.                CMP   AL,BL
  2106.                JE    wait_dma          ; no han pasado 256/1193180 seg
  2107.                MOV   BL,AL
  2108.                LOOP  wait_dma
  2109.  
  2110. io_timeout:    CALL  reset_fast        ; habilita ints (quita timeout)
  2111.                MOV   status,80h        ; recuperar condición timeout
  2112.                JMP   io_ret_nok
  2113. io_fin:        IN    AL,DX
  2114.                XOR   AL,11000000b
  2115.                TEST  AL,11000000b
  2116.                JZ    io_result         ; hay resultados del FDC
  2117.                CALL  reset_fast        ; habilita ints
  2118.                JMP   io_ret_ok         ; siempre ok
  2119. io_result:     CALL  reset_DMA         ; por si acaso
  2120.                STI
  2121.                LEA   BX,fdc_result
  2122.                PUSH  CX                ; ** no corromper CX
  2123.                MOV   CX,7
  2124. io_leeres:     CALL  fdc_read          ; leyendo resultados
  2125.                MOV   [BX],AL
  2126.                INC   BX
  2127.                LOOP  io_leeres
  2128.                POP   CX                ; **
  2129.                CMP   modoDMA,ON
  2130.                JE    io_ret_nok
  2131.                MOV   AL,status         ; preservar resultado
  2132.                CALL  reset_fast        ; volver al modo DMA+INT
  2133.                MOV   status,AL         ; restaurar resultado
  2134. io_ret_nok:    CALL  ajustar_hora
  2135.                XPOP  <DI, ES>          ; *
  2136.                STC                     ; retorno con error
  2137.                CALL  set_err
  2138.                RET
  2139. io_ret_ok:     XPOP  <DI, ES>          ; *
  2140.                CALL  ajustar_hora
  2141.                CLC                     ; retorno Ok
  2142.                RET
  2143. espia_dma      ENDP
  2144.  
  2145. ; ------------ Leer el reloj de tiempo real y actualizar la hora.
  2146. ;              El acceso a disco con las interrupciones inhibidas
  2147. ;              retrasa brutalmente la hora. Si es un PC/XT, a la
  2148. ;              entrada CX indica las veces que le quedaban por cambiar
  2149. ;              a la parte alta de la cuenta del contador 0 del 8253
  2150. ;              desde que se inhibieron las interrupciones para que
  2151. ;              se hubiera producido un timeout.
  2152.  
  2153. ajustar_hora   PROC
  2154.                XPUSHA
  2155.                CMP   CS:pcxt,ON
  2156.                JE    ajuste_burdo      ; jeje, pobrecillo XT
  2157.                CALL  leer_RTC
  2158.                JNC   actualiza_tm      ; no hay actualización en curso
  2159.                JMP   fin_ajuste
  2160. ajuste_burdo:  SUB   CX,TICSTIMEOUT
  2161.                NEG   CX                ; tiempo transcurrido apróx.
  2162.                ADD   CX,48             ; redondeo
  2163.                MOV   CL,CH
  2164.                MOV   CH,0
  2165.                SHR   CX,1              ; expresado en 1/18,2-avos seg.
  2166.                PUSH  DS
  2167.                DDS
  2168.                ADD   CX,DS:[6Ch]
  2169.                MOV   BX,DS:[6Eh]
  2170.                ADC   BX,0
  2171.                POP   DS
  2172.                JMP   ajusta_bios
  2173. actualiza_tm:  MOV   AL,DH             ; segundos en BCD
  2174.                CALL  convdec           ; BCD (AL) -> decimal (AX)
  2175.                PUSH  AX                ; almacenar segundos
  2176.                MOV   AL,CL             ; minuto en BCD
  2177.                CALL  convdec           ; BCD (AL) -> decimal (AX)
  2178.                PUSH  AX                ; almacenar minuto
  2179.                MOV   AL,CH             ; hora en BCD
  2180.                CALL  convdec           ; BCD (AL) -> decimal (AX)
  2181.                MOV   BX,60
  2182.                MUL   BL                ; AX = hora*60
  2183.                POP   DX
  2184.                ADD   AX,DX             ; AX = hora*60+minuto
  2185.                MUL   BX                ; DX:AX = (hora*60+minuto)*60
  2186.                POP   CX
  2187.                ADD   CX,AX             ; añadir segundos
  2188.                ADC   DX,0
  2189.                MOV   BX,DX             ; BX:CX segundos totales
  2190.                MOV   SI,CX
  2191.                MOV   DI,BX             ; DI:SI segundos totales
  2192.                MOV   AX,18             ; (1193180 DIV 65536)
  2193.                CALL  mult32x16         ; DI:SI = seg * 18
  2194.                XCHG  SI,CX
  2195.                XCHG  DI,BX             ; BX:CX:XX = seg * 18 * 65536
  2196.                MOV   AX,13532          ; (1193180 MOD 65536)
  2197.                CALL  mult32x16
  2198.                ADD   CX,DI
  2199.                ADC   BX,0              ; BX:CX:SI = seg * 1193180
  2200. ajusta_bios:   PUSH  DS
  2201.                DDS
  2202.                CMP   BX,24
  2203.                JNE   medianoche_ok
  2204.                CMP   CX,176
  2205.                JB    medianoche_ok
  2206.                XOR   BX,BX             
  2207.                SUB   CX,176
  2208.                INC   BYTE PTR DS:[70h] ; paso 23:59:59 --> 00:00:00
  2209. medianoche_ok: MOV   DS:[6Ch],CX
  2210.                MOV   DS:[6Eh],BX       ; BX:CX = seg * 1193180 / 65536
  2211.                POP   DS
  2212. fin_ajuste:    XPOPA
  2213.                RET
  2214. convdec:       MOV   AH,AL             ; BCD en AL --> decimal en AX
  2215.                SHR   AH,1
  2216.                SHR   AH,1
  2217.                SHR   AH,1
  2218.                SHR   AH,1
  2219.                AND   AL,15
  2220.                AAD
  2221.                RET
  2222. ajustar_hora   ENDP
  2223.  
  2224.                ; --- Obtener la hora del reloj de tiempo real SIN BIOS.
  2225.  
  2226. leer_RTC       PROC
  2227.                MOV   AL,0Ah            ; registro de estado A
  2228.                OUT   70h,AL
  2229.                DELAY
  2230.                IN    AL,71h
  2231.                TEST  AL,128
  2232.                JNZ   tm_nok            ; en medio de actualización
  2233.                MOV   AL,4
  2234.                DELAY
  2235.                OUT   70h,AL
  2236.                DELAY
  2237.                IN    AL,71h
  2238.                MOV   CH,AL             ; hora
  2239.                MOV   AL,2
  2240.                DELAY
  2241.                OUT   70h,AL
  2242.                DELAY
  2243.                IN    AL,71h
  2244.                MOV   CL,AL             ; minuto
  2245.                MOV   AL,0
  2246.                DELAY
  2247.                OUT   70h,AL
  2248.                DELAY
  2249.                IN    AL,71h
  2250.                MOV   DH,AL             ; segundo
  2251.                CLC
  2252.                RET
  2253. tm_nok:        STC
  2254.                RET
  2255. leer_RTC       ENDP
  2256.  
  2257. ; ------------ Rutina para multiplicar números de 32 por números de 16
  2258. ;              bits generando resultado de 48 bits: DXDISI = DISI * AX
  2259.  
  2260. mult32x16      PROC
  2261.                PUSH  AX
  2262.                XCHG  SI,AX    ; multiplicador en SI
  2263.                MUL   SI       ; AX (parte baja) * SI --> DXAX
  2264.                XPUSH <DX, AX> ; preservar resultado parcial
  2265.                MOV   AX,DI
  2266.                MUL   SI       ; AX (parte alta) * SI --> DXAX
  2267.                XPOP  <SI, DI> ; parte baja y media del resultado
  2268.                ADD   DI,AX    ; acumular resultado intermedio
  2269.                ADC   DX,0     ; arrastrar posible acarreo
  2270.                POP   AX
  2271.                RET
  2272. mult32x16      ENDP
  2273.  
  2274. ; ------------ Devolver en AH la página de DMA y en BX la base. A la
  2275. ;              entrada, AX:DI -> dirección de memoria.
  2276.  
  2277. calc_dir_DMA   PROC
  2278.                PUSH  DX
  2279.                MOV   BX,16
  2280.                MUL   BX
  2281.                ADD   AX,DI
  2282.                ADC   DX,0              ; DX:AX = dirección 20 bits
  2283.                MOV   BX,AX             ; base en BX
  2284.                MOV   AH,DL             ; página
  2285. dir_DMA_ok:    POP   DX
  2286.                RET
  2287. calc_dir_DMA   ENDP
  2288.  
  2289. ; ------------ Determinar el tipo de error producido en el acceso.
  2290.  
  2291. set_err        PROC
  2292.                XPUSHA
  2293.                JNC   err_ret           ; no hay error
  2294.                CMP   status,0          ; ¿'status' ya asignado?
  2295.                JNE   err_retc          ; no cambiarlo si es así
  2296.                MOV   AL,BYTE PTR fdc_result+1
  2297.                AND   AL,10110111b      ; aislar condiciones de test
  2298.                LEA   BX,lista_errs
  2299.                MOV   CX,9
  2300. busca_err:     MOV   AH,[BX]           ; código de error BIOS
  2301.                SHL   AL,1
  2302.                JC    err_ok            ; es ese error
  2303.                INC   BX
  2304.                LOOP  busca_err         ; buscar otro error
  2305. err_ok:        OR    status,AH
  2306. err_retc:      STC                     ; condición de error
  2307. err_ret:       XPOPA
  2308.                RET
  2309. set_err        ENDP
  2310.  
  2311. ; ------------ Esperar interrupción de disquete durante casi 2
  2312. ;              segundos antes de considerar que ha sido un fracaso.
  2313.  
  2314. espera_int     PROC
  2315.                STI
  2316.                XPUSHA
  2317.                XPUSH <DS, 40h>
  2318.                POP   DS
  2319.                MOV   AX,9001h
  2320.                CLC
  2321.                INT   15h               ; permitir multitarea
  2322.                JC    timeout_int
  2323.                MOV   AH,0FFh
  2324. esperar_int:   CMP   AL,DS:[6Ch]
  2325.                JE    mira_int
  2326.                MOV   AL,DS:[6Ch]
  2327.                INC   AH
  2328.                CMP   AH,37             ; ¿más de 2 segundos?
  2329.                JB    mira_int
  2330. timeout_int:   OR    CS:status,80h     ; timeout
  2331.                STC
  2332.                JMP   fin_espera
  2333. mira_int:      TEST  BYTE PTR DS:[3Eh],80h
  2334.                JZ    esperar_int
  2335.                AND   BYTE PTR DS:[3Eh],7Fh  ; CF=0
  2336. fin_espera:    POP   DS
  2337.                XPOPA
  2338.                RET
  2339. espera_int     ENDP
  2340.  
  2341. ; ------------ Preparar DMA para E/S. A la entrada, BX = dirección de
  2342. ;              base, AH = registro de página y CX = nº bytes - 1.
  2343.  
  2344. prepara_DMA    PROC
  2345.                CMP   modoDMA,ON
  2346.                JE    _prepara_DMA
  2347.                MOV   sentidoIO,AL
  2348.                MOV   bytesIO,CX
  2349.                INC   bytesIO
  2350.                RET                     ; modo NO-DMA
  2351. _prepara_DMA:  PUSH  AX
  2352.                CLI
  2353.                OUT   0Bh,AL            ; registro de modo del DMA
  2354.                MOV   AL,0
  2355.                DELAY
  2356.                OUT   0Ch,AL            ; clear first/last flip-flop
  2357.                MOV   AL,BL
  2358.                DELAY
  2359.                OUT   4,AL
  2360.                MOV   AL,BH
  2361.                DELAY
  2362.                OUT   4,AL              ; enviada dirección base
  2363.                DELAY
  2364.                MOV   AL,AH
  2365.                OUT   81h,AL            ; registro de página del DMA
  2366.                MOV   AL,CL
  2367.                DELAY
  2368.                OUT   5,AL
  2369.                MOV   AL,CH
  2370.                DELAY
  2371.                OUT   5,AL              ; enviada cuenta de bytes
  2372.                STI
  2373.                MOV   AL,2
  2374.                DELAY
  2375.                OUT   0Ah,AL            ; habilitar canal 2 de DMA
  2376.                POP   AX
  2377.                RET
  2378. prepara_DMA    ENDP
  2379.  
  2380. ; ------------ Recibir byte del FDC en AL. A la vuelta, CF=1 si
  2381. ;              la operación fracasó (el FDC no estaba listo) y
  2382. ;              se indica la condición de timeout en «status».
  2383.  
  2384. fdc_read       PROC
  2385.                CMP   CS:pcxt,ON
  2386.                JE    fdc_read_xt
  2387.                XPUSH <CX, DX, AX>
  2388.                CALL  fdc_respiro       ; no abrasar el FDC
  2389.                MOV   DX,FD_STATUS      ; registro de estado del FDC
  2390.                MOV   CX,133            ; constante para 0,002 segundos
  2391. espera_rd:     DELAY
  2392.                IN    AL,DX
  2393.                AND   AL,11000000b
  2394.                CMP   AL,11000000b      ; ¿dato listo?
  2395.                JE    fdc_rd_ok
  2396.                DELAY
  2397.                IN    AL,61h
  2398.                AND   AL,10h
  2399.                CMP   AL,AH
  2400.                JE    espera_rd         ; reintentarlo durante 15,09 µs
  2401.                MOV   AH,AL
  2402.                LOOP  espera_rd
  2403.                XPOP  <AX, DX, CX>
  2404.                OR    status,80h        ; timeout
  2405.                MOV   AL,0
  2406.                STC                     ; fallo
  2407.                RET
  2408. fdc_rd_ok:     POP   AX
  2409.                INC   DX                ; apuntar al registro de datos
  2410.                DELAY
  2411.                IN    AL,DX             ; leer byte del FDC
  2412.                XPOP  <DX, CX>
  2413.                CLC                     ; Ok
  2414.                RET
  2415. fdc_read       ENDP
  2416.  
  2417. fdc_read_xt    PROC
  2418.                XPUSH <CX, DX>
  2419.                MOV   DX,FD_STATUS      ; registro de estado del FDC
  2420.                XOR   CX,CX             ; evitar cuelgue total si falla
  2421. espera_rd_xt:  IN    AL,DX             ; leer registro de estado
  2422.                TEST  AL,80h            ; ¿bit 7 inactivo?
  2423.                LOOPZ espera_rd_xt      ; así es: el FDC está ocupado
  2424.                JCXZ  fdc_rd_nok_xt
  2425.                INC   DX                ; apuntar al registro de datos
  2426.                IN    AL,DX             ; leer byte del FDC
  2427.                CLC
  2428.                XPOP  <DX, CX>
  2429.                RET
  2430. fdc_rd_nok_xt: OR    status,80h        ; timeout
  2431.                STC
  2432.                XPOP  <DX, CX>
  2433.                RET
  2434. fdc_read_xt    ENDP
  2435.  
  2436. ; ------------ Enviar byte AL al FDC. A la vuelta, CF=1 si
  2437. ;              la operación fracasó (el FDC no estaba listo) y
  2438. ;              se indica la condición de timeout en «status».
  2439.  
  2440. fdc_write      PROC
  2441.                CMP   CS:pcxt,ON
  2442.                JE    fdc_write_xt
  2443.                XPUSH <CX, DX, AX>
  2444.                CALL  fdc_respiro       ; no abrasar el FDC
  2445.                MOV   DX,FD_STATUS      ; registro de estado del FDC
  2446.                MOV   CX,133            ; constante para 0,002 segundos
  2447. espera_wr:     DELAY
  2448.                IN    AL,DX
  2449.                TEST  AL,80h            ; ¿listo para E/S?
  2450.                JNZ   fdc_wr_ok
  2451.                DELAY
  2452.                IN    AL,61h
  2453.                AND   AL,10h
  2454.                CMP   AL,AH
  2455.                JE    espera_wr         ; reintentarlo durante 15,09 µs
  2456.                MOV   AH,AL
  2457.                LOOP  espera_wr
  2458.                XPOP  <AX, DX, CX>
  2459.                OR    status,80h        ; timeout
  2460.                STC                     ; fallo
  2461.                RET
  2462. fdc_wr_ok:     INC   DX                ; apuntar al registro de datos
  2463.                POP   AX
  2464.                DELAY
  2465.                OUT   DX,AL             ; enviar byte al FDC
  2466.                XPOP  <DX, CX>
  2467.                CLC                     ; Ok
  2468.                RET
  2469. fdc_write      ENDP
  2470.  
  2471. fdc_write_xt   PROC
  2472.                XPUSH <AX, CX, DX>
  2473.                MOV   DX,FD_STATUS      ; registro de estado del FDC
  2474.                XCHG  AH,AL             ; preservar AL en AH
  2475.                XOR   CX,CX             ; evitar cuelgue total si falla
  2476. espera_wr_xt:  IN    AL,DX             ; leer registro de estado
  2477.                TEST  AL,80h            ; ¿bit 7 inactivo?
  2478.                LOOPZ espera_wr_xt      ; así es: el FDC está ocupado
  2479.                JCXZ  fdc_wr_nok_xt
  2480.                XCHG  AH,AL             ; recuperar el dato de AL
  2481.                INC   DX                ; apuntar al registro de datos
  2482.                OUT   DX,AL             ; enviar byte al FDC
  2483.                XPOP  <DX, CX, AX>
  2484.                CLC
  2485.                RET
  2486. fdc_wr_nok_xt: OR    status,80h        ; timeout
  2487.                XPOP  <DX, CX, AX>
  2488.                STC
  2489.                RET
  2490. fdc_write_xt   ENDP
  2491.  
  2492. ; ------------ Retardo de 60 µs para dar tiempo al FDC en 486 rápidos.
  2493.  
  2494. fdc_respiro    PROC
  2495.                CMP   CS:pcxt,ON
  2496.                JNE   fdc_resp_at
  2497.                PUSH  CX
  2498.                MOV   CX,50
  2499. respiro:       LOOP  respiro           ; retardo en PC/XT
  2500.                POP   CX
  2501.                RET
  2502. fdc_resp_at:   XPUSH <AX, CX>
  2503.                MOV   CX,4
  2504. fdc_ret:       PMICRO
  2505.                LOOP  fdc_ret
  2506.                XPOP  <CX, AX>
  2507.                RET
  2508. fdc_respiro    ENDP
  2509.  
  2510. ; ------------ Esperar exactamente AX milisegundos.
  2511.  
  2512. retardo        PROC
  2513.                PUSHF
  2514.                XPUSHA
  2515.                CMP   CS:pcxt,ON
  2516.                JE    retardo_xt
  2517.                MOV   DX,16970          ; 16970 = 1193180/18*256/1000
  2518.                MUL   DX
  2519.                MOV   CL,AH             ; dividir DX:AX entre 256 y
  2520.                MOV   CH,DL             ; dejar el resultado en DX:CX
  2521.                MOV   DL,DH
  2522.                MOV   DH,0              ; DX:CX 15,09 µs-avos
  2523. retardando:    PMICRO
  2524.                LOOP  retardando
  2525.                AND   DX,DX
  2526.                JZ    retardado
  2527.                DEC   DX
  2528.                JMP   retardando
  2529. retardado:     XPOPA
  2530.                POPF
  2531.                RET
  2532.  
  2533. retardo_xt:    CMP   AX,54             ; como máximo 54 ms cada vez
  2534.                JBE   retarda_fin
  2535.                PUSH  AX
  2536.                MOV   AX,54
  2537.                CALL  rt_ax
  2538.                POP   AX
  2539.                SUB   AX,54
  2540.                JMP   retardo_xt
  2541. retarda_fin:   CALL  rt_ax
  2542.                JMP   retardado
  2543.  
  2544. rt_ax:         MOV   DX,1000           ; retardo de hasta 54 ms
  2545.                MUL   DX
  2546.                MUL   CS:tbase
  2547.                MOV   CX,54925
  2548.                DIV   CX                ; AX = contador iteraciones
  2549.                MOV   CX,AX
  2550.                EVEN                    ; forzar alineamiento
  2551. retarda:       DEC   CX
  2552.                JMP   SHORT $+2
  2553.                JNZ   retarda
  2554.                RET
  2555. retardo        ENDP
  2556.  
  2557.                EVEN
  2558. ini_buffer     EQU   $  ; comienzo del buffer E/S
  2559.  
  2560. fin_residente  EQU   $  ; fin del área residente sin contar el buffer
  2561.  
  2562. bytes_resid    EQU   fin_residente-ini_residente
  2563.  
  2564.  
  2565.  
  2566. ; ****************************************************************
  2567. ; *                                                              *
  2568. ; *   I N S T A L A C I O N    D E S D E    E L    C O N F I G   *
  2569. ; *                                                              *
  2570. ; ****************************************************************
  2571.  
  2572. init           PROC
  2573.                LEA   DX,retorno_ok
  2574.                MOV   CS:p_rutinas,DX        ; anular 'init'
  2575.  
  2576.                LES   BP,[BX].bpb_cmd        ; apuntar a los parámetros
  2577.                LEA   AX,bpb_ptrs
  2578.                MOV   [BX].bpb_cmd_desp,AX
  2579.                MOV   [BX].bpb_cmd_segm,CS   ; tabla punteros a BPB's
  2580.                XPUSH <DS, BX>
  2581.                PUSH  CS
  2582.                POP   DS                     ; DS: -> _PRINCIPAL
  2583.                MOV   BX,BP
  2584.                CALL  salta_nombre
  2585.                LEA   BP,parametros
  2586.                CALL  obtener_param
  2587.                CALL  testAT
  2588.                JC    init_m1                ; en PC/XT, siempre DMA
  2589.                CMP   param_nodma,OFF
  2590.                JE    init_m1
  2591.                MOV   modoDMA,OFF            ; en AT, permitir NO-DMA
  2592.  
  2593. init_m1:       CALL  inic_general
  2594.                CMP   param_b,ON
  2595.                JNE   init_m2
  2596.                MOV   AX,tpista              ; /B permite modificar el
  2597.                MOV   tbuffer,AX             ;    tamaño del buffer
  2598. init_m2:       CALL  inic_ioctl
  2599.                MOV   AL,num_discos
  2600.                XPOP  <BX, DS>
  2601.                MOV   [BX].num_disc_init,AL
  2602.                MOV   AH,[BX].nuevo_disco    ; unidad en DOS 3.0+
  2603.                XPUSH <CS, CS>
  2604.                XPOP  <DS, ES>               ; DS y ES: -> _PRINCIPAL
  2605.                TEST  error,0FFFFh
  2606.                JZ    cont_instala1
  2607.                JMP   salida_error
  2608. cont_instala1: MOV   unidad_base,AH
  2609.                CALL  genera_nombre          ; de AL unidades desde AH
  2610.                CALL  analiza_equipo         ; ¿ordenador adecuado?
  2611.                TEST  error,0FFFFh
  2612.                JZ    cont_instala2
  2613.                JMP   salida_error
  2614. cont_instala2: CMP   instalado,ON
  2615.                JNE   cont_instala3
  2616.                OR    error,YAINST
  2617.                JMP   salida_error
  2618. cont_instala3: CALL  mx_get_handle          ; obtener código Multiplex
  2619.                JNC   handle_ok
  2620.                OR    error,MX64FULL         ; no quedan entradas
  2621.                JMP   salida_error
  2622. handle_ok:     MOV   multiplex_id,AH        ; entrada multiplex
  2623.                CALL  preservar_ints         ; tomar nota de vectores
  2624.                LEA   BX,ini_buffer+15
  2625.                MOV   CL,4
  2626.                SHR   BX,CL
  2627.                MOV   AX,CS
  2628.                ADD   AX,BX
  2629.                MOV   sbuffer,AX
  2630.                MOV   sbuf512,AX
  2631.                CMP   param_nodma,ON
  2632.                JNE   usar_dma               ; DMA usado
  2633.                CMP   param_ems,ON
  2634.                JNE   init_tsr
  2635.                CALL  alloc_EMS              ; poner buffer en EMS
  2636.                JMP   init_tsr
  2637. usar_dma:      MOV   BX,tbuffer
  2638.                CALL  getdmaok
  2639.                AND   BX,BX
  2640.                JZ    dmaguay                ; no hay problemas de DMA
  2641.                MOV   sbuffer,AX             ; arreglar cruce frontera
  2642.                MOV   sbuf512,AX
  2643.                ADD   tbuffer,BX
  2644.                OR    error,DMACRUCE         ; ¡maldita frontera!
  2645. dmaguay:       CALL  vds_dma_ok?
  2646.                MOV   emmtipo,BX             ; tipo de EMM
  2647.                JNC   init_tsr
  2648.                OR    error,DMAPOCO          ; poco buffer DMA en EMM
  2649. init_tsr:      CALL  inicializa_id
  2650.                MOV   DI,100h                ; ORG 0 (compensar COM)
  2651.                CALL  activar_ints           ; interceptar vectores
  2652.                LEA   DX,programa_txt        ; mensaje de instalación
  2653.                CALL  print
  2654.                LEA   DX,instalado_txt
  2655.                CALL  print
  2656.                CMP   pcxt,ON
  2657.                JNE   ins_at
  2658.                CMP   param_nodma,OFF
  2659.                JE    ins_at
  2660.                LEA   DX,errxtdma_txt        ; PC/XT necesita DMA
  2661.                CALL  print
  2662. ins_at:        TEST  error,DMACRUCE
  2663.                JZ    buffernormal
  2664.                LEA   DX,dma_front_txt
  2665.                CALL  print                  ; aviso de frontera DMA
  2666. buffernormal:  TEST  error,DMAPOCO
  2667.                JZ    bastantedma
  2668.                LEA   DX,dma_poco_txt
  2669.                CALL  print                  ; aviso de poco buffer DMA
  2670.                CMP   emmtipo,"QE"
  2671.                LEA   DX,crlf_txt
  2672.                JNE   pr_emm
  2673.                LEA   DX,emm_qemm_txt
  2674. pr_emm:        CALL  print                  ; informar de QEMM
  2675. bastantedma:   CMP   param_ems,ON
  2676.                JNE   ems_ok
  2677.                CMP   ems_handle,0
  2678.                JNE   ems_ok
  2679.                LEA   DX,erremsins_txt
  2680.                CMP   param_nodma,ON
  2681.                JE    err_ems_ok
  2682.                LEA   DX,erremsdma_txt
  2683. err_ems_ok:    CALL  print
  2684. ems_ok:        MOV   AX,longitud_total
  2685.                MOV   CL,4
  2686.                SHL   AX,CL
  2687.                LDS   BX,CS:pcab_peticion
  2688.                MOV   [BX].fin_resid_desp,AX
  2689.                MOV   [BX].fin_resid_segm,CS
  2690.                MOV   AX,100h                ; instalación Ok.
  2691.                RET
  2692. salida_error:  LEA   DX,programa_txt
  2693.                CALL  print
  2694.                LEA   DX,mal_dos_txt         ; errores posibles
  2695.                TEST  error,MALDOS           ; desde el CONFIG
  2696.                JNZ   prn_error
  2697.                LEA   DX,mal_bios_txt
  2698.                TEST  error,MALBIOS
  2699.                JNZ   prn_error
  2700.                LEA   DX,mal_drv_txt
  2701.                TEST  error,MALDRV
  2702.                JNZ   prn_error
  2703.                LEA   DX,err_sintax_txt
  2704.                TEST  error,ERRSINTAX        ; ¿error de sintaxis?
  2705.                JNZ   prn_error
  2706.                LEA   DX,nocabe_txt
  2707.                TEST  error,MX64FULL
  2708.                JNZ   prn_error
  2709.                LEA   DX,ya_ins_txt
  2710. prn_error:     CALL  print                  ; imprimir error
  2711.                LDS   BX,CS:pcab_peticion
  2712.                MOV   [BX].fin_resid_desp,0  ; OFFSET 0 indica que no
  2713.                MOV   [BX].fin_resid_segm,CS ; quedará instalado
  2714.                MOV   AX,100h                ; indicar retorno correcto
  2715.                RET
  2716. init           ENDP
  2717.  
  2718.  
  2719. ; ********************************************************************
  2720. ; *                                                                  *
  2721. ; *   C O D I G O    E J E C U T A D O    D E S D E    E L    D O S  *
  2722. ; *                                                                  *
  2723. ; ********************************************************************
  2724.  
  2725. main           PROC  FAR
  2726.                MOV   BX,_PILA
  2727.                SUB   BX,_PRINCIPAL          ; tamaño de este programa
  2728.                ADD   BX,tampila/16+17       ; más pila y más PSP
  2729.                MOV   AH,4Ah                 ; cambiar memoria asignada
  2730.                INT   21h
  2731.                MOV   AX,_PRINCIPAL          ; programa de un segmento
  2732.                MOV   DS,AX                  ; DS: -> _PRINCIPAL
  2733.                LEA   BP,parametros
  2734.                MOV   BX,81h
  2735.                MOV   psp,ES                 ; anotar PSP
  2736.                CALL  obtener_param          ; procesar parámetros
  2737.                PUSH  DS
  2738.                POP   ES                     ; ES: -> _PRINCIPAL
  2739.                JNC   test_pmts
  2740.                JMP   informar               ; error/ayuda
  2741. test_pmts:     CMP   param_nodma,ON
  2742.                JNE   cont_ins
  2743.                CMP   param_test,ON
  2744.                JE    cont_ins
  2745. pmt_config:    OR    error,PARAMCONFIG      ; parámetro del CONFIG.SYS
  2746.                JMP   informar
  2747. cont_ins:      CMP   param_ems,ON
  2748.                JE    pmt_config
  2749.                CALL  null_param?
  2750.                JNE   proceder
  2751.                CALL  analiza_equipo
  2752.                CMP   instalado,ON
  2753.                JNE   ayudar                 ; no instalado y sin parámetros
  2754.                CALL  adaptar_param          ; parámetros en copia residente
  2755.                CALL  informe                ; informe de unidades/opciones
  2756.                JMP   fin
  2757. ayudar:        MOV   param_ayuda,ON
  2758.                JMP   informar               ; no indicados parámetros
  2759. proceder:      CALL  inic_general
  2760.                CALL  analiza_equipo
  2761.                TEST  error,0FFFFh XOR MALDRV
  2762.                JNZ   informar               ; error != MALDRV
  2763.                CALL  adaptar_param          ; parámetros en copia residente
  2764.                CMP   param_test,ON
  2765.                JE    testear
  2766.                CMP   instalado,ON
  2767.                JE    ya_reside
  2768.                OR    error,NOINST           ; programa no instalado
  2769.                JMP   informar               ; (obligarlo para formatear)
  2770. ya_reside:     CALL  setbuffer
  2771.                JC    informar
  2772.                MOV   AL,maxpistas
  2773.                CMP   frontera,AL
  2774.                JBE   fr_ok
  2775.                MOV   frontera,AL            ; limitar alcance frontera
  2776. fr_ok:         CALL  format_disk
  2777.                JMP   fin
  2778. testear:       CALL  setbuffer
  2779.                JC    informar
  2780.                CALL  test_disk              ; calcular mayor capacidad
  2781.                JMP   fin
  2782. informar:      CALL  info
  2783.                MOV   AX,error
  2784. fin:           MOV   AH,4Ch
  2785.                INT   21h                    ; final
  2786. main           ENDP
  2787.  
  2788.  
  2789. ;*********************************************************
  2790. ;*                                                       *
  2791. ;*  SUBRUTINAS DE PROPOSITO GENERAL PARA LA INSTALACION  *
  2792. ;*                                                       *
  2793. ;*********************************************************
  2794.  
  2795.                INCLUDE 2MUTIL.INC
  2796.  
  2797. ; ------------ Saltar nombre del driver en línea de órdenes del CONFIG
  2798.  
  2799. salta_nombre   PROC
  2800.                MOV   AL,ES:[BX]        
  2801.                INC   BX
  2802.                CMP   AL,' '
  2803.                JE    fin_nombre
  2804.                CMP   AL,9
  2805.                JE    fin_nombre
  2806.                CMP   AL,0Dh
  2807.                JE    fin_nombre
  2808.                CMP   AL,0Ah
  2809.                JE    fin_nombre
  2810.                AND   AL,AL
  2811.                JZ    fin_nombre
  2812.                JMP   salta_nombre
  2813. fin_nombre:    RET
  2814. salta_nombre   ENDP
  2815.  
  2816. ; ------------ Nombrar las unidades (AL) a partir de la número AH.
  2817.  
  2818. genera_nombre  PROC
  2819.                MOV   CL,AL
  2820.                MOV   CH,0                   ; CX = nº unidades
  2821.                MOV   AL,AH
  2822.                ADD   AL,'A'
  2823.                MOV   AH,':'
  2824.                LEA   SI,tabla_letras1
  2825.                LEA   DI,tabla_letras2
  2826. init_nombres:  MOV   [SI],AX
  2827.                MOV   [DI],AX
  2828.                ADD   SI,3
  2829.                ADD   DI,3
  2830.                INC   AL
  2831.                LOOP  init_nombres
  2832.                RET
  2833. genera_nombre  ENDP
  2834.  
  2835. ; ------------ Inicializar ciertas variables.
  2836.  
  2837. inic_general   PROC
  2838.                CALL  testDRDOS
  2839.                CALL  testAT
  2840.                JNC   skip_tmtest       ; en AT no calcularlo [*]
  2841.                CALL  cte_tiempos
  2842.                MOV   tbase,AX          ; cte. retardo para 1/18,2 seg.
  2843. skip_tmtest:
  2844.                MOV   num_discos,0
  2845.                MOV   DL,0
  2846.                CALL  tipo_disco
  2847.                JNC   hay_unidad
  2848.                MOV   DL,1
  2849.                CALL  tipo_disco
  2850.                JNC   hay_unidad
  2851.                OR    error,MALBIOS     ; no hay disqueteras
  2852.                RET
  2853. hay_unidad:    MOV   disco,0
  2854.                MOV   DL,disco
  2855.                CALL  tipo_disco
  2856.                CMP   BL,2
  2857.                JE    tipoE_HD
  2858.                CMP   BL,4
  2859.                JAE   tipoE_HD          ; hallada A: de alta densidad
  2860.                INC   disco
  2861.                MOV   DL,disco
  2862.                CALL  tipo_disco
  2863.                CMP   BL,2
  2864.                JE    tipoE_HD
  2865.                CMP   BL,4
  2866.                JAE   tipoE_HD          ; hallada B: de alta densidad
  2867.                OR    error,MALDRV
  2868.                RET
  2869. tipoE_HD:      MOV   info_E.tipo_drv,BL  ; guardar tipo unidad
  2870.                MOV   AL,disco
  2871.                MOV   info_E.unidad,AL    ; y si es la A: ó B:
  2872.                ADD   info_E.ioctl_id,AL
  2873.                INC   num_discos          ; de momento, 1 unidad
  2874.                CMP   AL,1
  2875.                JE    fin_inic            ; procesadas A: y B:
  2876.                MOV   DL,1
  2877.                CALL  tipo_disco
  2878.                CMP   BL,2
  2879.                JE    tipoF_HD
  2880.                CMP   BL,4
  2881.                JB    fin_inic            ; hallada B: de alta densidad
  2882. tipoF_HD:      MOV   info_F.tipo_drv,BL  ; guardar tipo unidad
  2883.                MOV   info_F.unidad,1     ; y que es la B:
  2884.                ADD   info_F.ioctl_id,1
  2885.                INC   num_discos          ; 2 unidades controladas
  2886.  
  2887. fin_inic:      MOV   AX,m_35_ed          ; buffer para 2.88M
  2888.                CMP   info_E.tipo_drv,5
  2889.                JAE   inic_buff
  2890.                CMP   info_F.tipo_drv,5
  2891.                JAE   inic_buff
  2892.                MOV   AX,m_35_hd          ; buffer para 1.44M
  2893.                CMP   info_E.tipo_drv,4
  2894.                JE    inic_buff
  2895.                CMP   info_F.tipo_drv,4
  2896.                JE    inic_buff
  2897.                MOV   AX,m_525_hd         ; buffer para 1.2M
  2898. inic_buff:     MOV   tbuffer,AX
  2899.                RET
  2900. inic_general   ENDP
  2901.  
  2902.                ; --- Comprobar si es DR-DOS 6.0 ó Novell DOS 7.0
  2903.  
  2904. testDRDOS      PROC
  2905.                MOV   AX,4452h
  2906.                INT   21h
  2907.                JC    drdos_tst
  2908.                CMP   AL,67h
  2909.                JB    drdos_tst
  2910.                MOV   drdos6,ON         ; DR-DOS 6 / Novell DOS 7
  2911. drdos_tst:     RET
  2912. testDRDOS      ENDP
  2913.  
  2914. ; ------------ Inicializar la información IOCTL de las unidades.
  2915. ;              Se asume que sólo DS apunta a los datos.
  2916.  
  2917. inic_ioctl     PROC
  2918.                PUSH  ES                ; *
  2919.                PUSH  DS
  2920.                POP   ES
  2921.                LEA   DI,info_E
  2922.                CALL  inic_ioct_DI
  2923.                LEA   DI,info_F
  2924.                CALL  inic_ioct_DI
  2925.                POP   ES                ; *
  2926.                RET
  2927.  
  2928. inic_ioct_DI:  MOV   AL,[DI].tipo_drv
  2929.                LEA   SI,info_drv288
  2930.                CMP   AL,5
  2931.                JAE   info_drv_ok
  2932.                LEA   SI,info_drv120
  2933.                CMP   AL,2
  2934.                JE    info_drv_ok
  2935.                LEA   SI,info_drv144
  2936. info_drv_ok:   MOV   CX,6
  2937.                CLD
  2938.                REP   MOVSB
  2939.                INC   SI                ; respetar byte tipo soporte
  2940.                INC   DI
  2941.                MOV   CX,31
  2942.                REP   MOVSB
  2943.                RET
  2944. inic_ioctl     ENDP
  2945.  
  2946. ; ------------ Comprobar que la configuración es la adecuada.
  2947.  
  2948. analiza_equipo PROC
  2949.                CALL  residente?
  2950.                MOV   AL,OFF
  2951.                JC    set_resid
  2952.                MOV   AL,ON
  2953. set_resid:     MOV   instalado,AL
  2954.                MOV   AH,30h
  2955.                INT   21h
  2956.                XCHG  AH,AL
  2957.                CMP   AX,31Eh           ; ¿DOS 3.30 o superior?
  2958.                MOV   AX,MALDOS
  2959.                JB    pc_nok
  2960.                CALL  testAT
  2961.                MOV   pcxt,OFF
  2962.                JNC   pc_ok
  2963.                MOV   pcxt,ON
  2964.                JMP   pc_ok
  2965. pc_nok:        OR    error,AX
  2966. pc_ok:         RET
  2967. analiza_equipo ENDP
  2968.  
  2969.                ; ----- Detectar 286 ó superior.
  2970.  
  2971. testAT         PROC
  2972.                PUSHF
  2973.                POP   AX
  2974.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  2975.                PUSH  AX            ; del registro de estado
  2976.                POPF
  2977.                PUSHF
  2978.                POP   AX
  2979.                AND   AH,0F0h
  2980.                CMP   AH,0F0h
  2981.                JE    testedAT
  2982.                STC
  2983. testedAT:      CMC                 ; CF = 0 en AT y 1 en PC/XT
  2984.                RET
  2985. testAT         ENDP
  2986.  
  2987. ; ------------ Comprobar si es un 386+
  2988.  
  2989. es386?         PROC
  2990.                PUSHF
  2991.                POP   AX
  2992.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  2993.                PUSH  AX            ; del registro de estado
  2994.                POPF
  2995.                PUSHF
  2996.                POP   AX
  2997.                AND   AH,0F0h
  2998.                CMP   AH,0F0h
  2999.                MOV   AL,0
  3000.                JE    fin_test_CPU  ; es 8086 o similar
  3001.                AND   AH,70h        ; 286 pone bits 12, 13 y 14 a cero
  3002.                JZ    fin_test_CPU  ; es 286
  3003.                MOV   AL,1          ; 386 o superior
  3004. fin_test_CPU:  MOV   AH,0
  3005.                CMP   AX,1
  3006.                RET
  3007. es386?         ENDP
  3008.  
  3009. ; ------------ Calcular la constante de retardo básica para perder
  3010. ;              exactamente 54,925 ms. Con una regla de 3 se podrá
  3011. ;              después aplicar para hacer retardos de milisegundos
  3012. ;              en los PC/XT.
  3013.  
  3014. cte_tiempos    PROC
  3015.                XPUSH <DS, ES, BX, CX, DX>
  3016.                MOV   AX,3508h
  3017.                INT   21h
  3018.                XPUSH <ES, BX>          ; preservar vector de INT 8
  3019.                PUSH  DS
  3020.                MOV   AX,40h
  3021.                MOV   DS,AX
  3022.                MOV   AL,DS:[6Ch]
  3023. espera_i8:     CMP   AL,DS:[6Ch]
  3024.                JE    espera_i8         ; esperar INT 8 ... para que no
  3025.                POP   DS
  3026.                LEA   DX,i8_crono       ; venga otra en un buen rato...
  3027.                MOV   AX,2508h
  3028.                INT   21h               ; nueva rutina de INT 8
  3029.                IN    AL,21h
  3030.                PUSH  AX                ; preservar estado de IRQ's
  3031.                MOV   AL,11111110b
  3032.                OUT   21h,AL            ; permitir sólo IRQ0
  3033.                MOV   AH,0              ; fase
  3034.                MOV   CX,0              ; contador
  3035.                MOV   BX,CX             ; seguiría a 0 si fallara
  3036.                EVEN                    ; forzar alineamiento
  3037. cuenta_iter:   DEC   CX                ; <─┐ bucle básico de retardo
  3038.                JMP   SHORT $+2         ;   │
  3039.                JNZ   cuenta_iter       ; <─┘ lo interrumpirá INT 8
  3040.                POP   AX                ; anterior estado de IRQ's
  3041.                OUT   21h,AL
  3042.                XPOP  <DX, DS>
  3043.                PUSH  BX                ; valor real contado
  3044.                MOV   AX,2508h          ; restaurar vector de INT 8
  3045.                INT   21h
  3046.                POP   AX                ; (65536-AX) vueltas en 54,9 ms
  3047.                NEG   AX                ; constante de retardo básica
  3048.                XPOP  <DX, CX, BX, ES, DS>
  3049.                RET
  3050. i8_crono:      INC   AH                ; nueva INT 8 que interrumpe
  3051.                CMP   AH,1              ; el bucle de retardo
  3052.                JE    fase1
  3053.                CMP   AH,2
  3054.                JE    fase2
  3055. i8_exit:       MOV   AL,20h
  3056.                OUT   20h,AL
  3057.                IRET
  3058. fase1:         MOV   CX,0              ; sincronizar con el reloj
  3059.                JMP   i8_exit
  3060. fase2:         MOV   BX,CX             ; anotar constante de retardo
  3061.                MOV   CX,1              ; forzar fin del bucle
  3062.                JMP   i8_exit
  3063. cte_tiempos    ENDP
  3064.  
  3065. ; ------------ Inicializar área «program_id» del programa residente.
  3066.  
  3067. inicializa_id  PROC
  3068.                MOV   segmento_real,CS  ; anotar segmento del bloque
  3069.                MOV   offset_real,0     ; ídem con el offset
  3070.                MOV   AX,bytes_resid    ; tamaño área residente
  3071.                ADD   AX,tbuffer        ; tamaño buffer residente
  3072.                ADD   AX,31             ; redondeo (programa+buffer)
  3073.                CMP   ems_handle,0
  3074.                JE    mem_AX
  3075.                MOV   AX,bytes_resid    ; tamaño área residente
  3076.                ADD   AX,512+SYSBYTES+GAPDEF+31  ; minibuffer+redondeo
  3077. mem_AX:        MOV   CL,4
  3078.                SHR   AX,CL
  3079.                MOV   longitud_total,AX
  3080.                OR    info_extra,3      ; SYS en formato EXE
  3081.                RET
  3082. inicializa_id  ENDP
  3083.  
  3084. ; ------------ Ubicar el buffer interno en EMS.
  3085.  
  3086. alloc_EMS      PROC
  3087.                PUSH  ES
  3088.                MOV   AX,3567h
  3089.                INT   21h               ; vector de INT 67h en ES:BX
  3090.                MOV   DI,10
  3091.                LEA   SI,emm_id
  3092.                MOV   CX,8
  3093.                CLD
  3094.                REP   CMPSB             ; ¿instalado controlador EMS?
  3095.                POP   ES
  3096.                JE    hay_emm
  3097.                JMP   finprep_emm
  3098. hay_emm:       MOV   CX,8000h          ; nº de intentos prudente
  3099. emm_llama:     MOV   AH,40h
  3100.                INT   67h
  3101.                AND   AH,AH
  3102.                JZ    emm_responde
  3103.                CMP   AH,82h
  3104.                LOOPE emm_llama
  3105.                JMP   finprep_emm       ; no funciona ¿?
  3106. emm_responde:  MOV   AH,41h
  3107.                INT   67h
  3108.                AND   AH,AH
  3109.                JZ    emm_pag_ok
  3110.                CMP   AH,82h
  3111.                JE    emm_responde      ; reintentar (EMM ocupado)
  3112.                JMP   finprep_emm
  3113. emm_pag_ok:    MOV   marco_ems,BX      ; inicializar marco EMS
  3114.                MOV   AH,46h
  3115.                INT   67h               ; obtener versión del EMM
  3116.                CMP   AL,40h
  3117.                JB    emm_obt_kb        ; versión anterior a la 4.0
  3118.                MOV   ems4,ON
  3119. emm_obt_pag:   XPUSH <ES,DS>
  3120.                POP   ES
  3121.                MOV   AX,5800h          ; obtener dirección de páginas
  3122.                LEA   DI,buffer_aux
  3123.                INT   67h
  3124.                POP   ES
  3125.                AND   AH,AH
  3126.                JZ    emm_pags_ok
  3127.                CMP   AH,82h
  3128.                JE    emm_obt_pag
  3129.                JMP   finprep_emm
  3130. emm_pags_ok:   LEA   SI,buffer_aux
  3131.                CLD
  3132. emm_otra_pag:  LODSW
  3133.                MOV   BX,AX             ; BX = segmento de la página
  3134.                LODSW                   ; AX = nº de la página
  3135.                AND   AX,AX
  3136.                JE    hallada_pag0      ; encontrada página 0
  3137.                LOOP  emm_otra_pag
  3138.                JMP   finprep_emm
  3139. hallada_pag0:  LODSW                   ; segmento página 1
  3140.                SUB   AX,BX
  3141.                CMP   AX,1024           ; ¿(pag1 - pag0) != 1024?
  3142.                JNE   finprep_emm       ; páginas no contiguas
  3143.                LODSW
  3144.                LODSW                   ; segmento página 2
  3145.                SUB   AX,BX
  3146.                CMP   AX,2048           ; ¿(pag2 - pag0) != 2048?
  3147.                JNE   finprep_emm       ; páginas no contiguas
  3148.                LODSW
  3149.                LODSW                   ; segmento página 3
  3150.                SUB   AX,BX
  3151.                CMP   AX,3072           ; ¿(pag3 - pag0) != 3072?
  3152.                JNE   finprep_emm       ; páginas no contiguas
  3153. emm_obt_kb:    MOV   BX,tbuffer
  3154.                ADD   BX,16383          ; BXi = redondeo
  3155.                ROL   BX,1
  3156.                ROL   BX,1
  3157.                AND   BX,3              ; BX = BXi / 16384
  3158.                MOV   AH,43h
  3159.                INT   67h
  3160.                AND   AH,AH
  3161.                JZ    ems_alloc_ok
  3162.                CMP   AH,82h
  3163.                JE    emm_obt_kb        ; reintentar (EMM ocupado)
  3164.                JMP   finprep_emm
  3165. ems_alloc_ok:  MOV   ems_handle,DX
  3166.                CMP   ems4,ON
  3167.                JNE   finprep_emm
  3168.                MOV   AX,5301h
  3169.                LEA   SI,emm_nombre
  3170.                INT   67h
  3171. finprep_emm:   RET
  3172. alloc_ems      ENDP
  3173.  
  3174. ; ------------ Devolver ZF=1 si no se indica ningún parámetro.
  3175.  
  3176. null_param?    PROC
  3177.                MOV   AH,param_ayuda
  3178.                OR    AH,param_dd
  3179.                OR    AH,param_dh
  3180.                OR    AH,param_ed
  3181.                OR    AH,param_k
  3182.                OR    AH,param_n
  3183.                OR    AH,param_test
  3184.                OR    AH,param_t
  3185.                OR    AH,param_r
  3186.                OR    AH,param_s
  3187.                OR    AH,param_f
  3188.                OR    AH,param_b
  3189.                OR    AH,param_x
  3190.                OR    AH,param_y
  3191.                OR    AH,param_m
  3192.                NOT   AH
  3193.                MOV   AL,disquetera
  3194.                XOR   AX,ptr_label
  3195.                XOR   AX,ptr_ilabel
  3196.                CMP   AX,-1
  3197.                RET
  3198. null_param?    ENDP
  3199.  
  3200. ; ------------ Informar al usuario.
  3201.  
  3202. info           PROC
  3203.                CMP   param_ayuda,ON    ; ¿solicitud de ayuda?
  3204.                JNE   info_normal
  3205.                LEA   DX,ayuda_txt
  3206.                CALL  print
  3207.                JNC   fin_info
  3208.                LEA   DX,limpia_txt     ; se pulsó ESC en la ayuda
  3209.                CALL  print
  3210.                JMP   fin_info
  3211. info_normal:   LEA   DX,programa_txt
  3212.                CALL  print
  3213.                LEA   DX,mal_dos_txt
  3214.                TEST  error,MALDOS      ; ¿DOS incorrecto?
  3215.                JZ    otroerr2
  3216.                CALL  print
  3217. otroerr2:      LEA   DX,mal_bios_txt
  3218.                TEST  error,MALBIOS     ; ¿BIOS obsoleta?
  3219.                JZ    otroerr3
  3220.                CALL  print
  3221. otroerr3:      LEA   DX,err_sintax_txt
  3222.                TEST  error,ERRSINTAX   ; ¿error de sintaxis?
  3223.                JZ    otroerr4
  3224.                CALL  print
  3225.                LEA   DX,pet_ayuda_txt
  3226.                CALL  print
  3227. otroerr4:      LEA   DX,no_ins_txt
  3228.                TEST  error,NOINST      ; ¿no instalado en CONFIG?
  3229.                JZ    otroerr5
  3230.                CALL  print
  3231. otroerr5:      LEA   DX,err_mem_txt
  3232.                TEST  error,POCAMEM     ; ¿poca memoria?
  3233.                JZ    otroerr6
  3234.                CALL  print
  3235. otroerr6:      LEA   DX,pconfig_txt
  3236.                TEST  error,PARAMCONFIG ; ¿parámetro del CONFIG?
  3237.                JZ    fin_info
  3238.                CALL  print
  3239. fin_info:      RET
  3240. info           ENDP
  3241.  
  3242. ; ------------ Establecer el buffer que no cruce con el DMA.
  3243.  
  3244. setbuffer      PROC
  3245.                MOV   AH,48h
  3246.                MOV   BX,MPISTA*2/16
  3247.                INT   21h
  3248.                JNC   haymem
  3249.                OR    error,POCAMEM
  3250.                STC
  3251.                RET
  3252. haymem:        MOV   BX,MPISTA         ; mayor buffer posible
  3253.                CALL  getdmaok          ; AX = segmento no conflictivo
  3254.                MOV   sbuffer,AX
  3255.                MOV   sbuf512,AX
  3256.                CLC
  3257.                RET
  3258. setbuffer      ENDP
  3259.  
  3260. ; ------------ Obtener un segmento no conflictivo con el DMA. A la
  3261. ;              entrada, AX=segmento propuesto y BX=tamaño buffer en
  3262. ;              bytes. A la salida, AX podría haber sido incrementado
  3263. ;              y BX indicaría en cuántos bytes.
  3264.  
  3265. getdmaok       PROC
  3266.                XPUSH <CX, DX>
  3267.                SHR   BX,1
  3268.                SHR   BX,1
  3269.                SHR   BX,1
  3270.                SHR   BX,1              ; bytes tamaño -> párrafos
  3271.                MOV   CX,AX
  3272.                MOV   DX,BX
  3273.                ADD   DX,AX             ; DX = segmento final
  3274.                AND   DH,0F0h           ; página del segmento final
  3275.                AND   CH,0F0h           ; página del segmento inicial
  3276.                MOV   BX,0              ; supuesto ajuste nulo
  3277.                CMP   CH,DH
  3278.                JE    buff_ok           ; no hay problemas con DMA
  3279.                MOV   DL,0              ; DX = nuevo segmento
  3280.                MOV   BX,DX
  3281.                SUB   BX,AX             ; incremento relativo
  3282.                MOV   AX,DX
  3283. buff_ok:       MOV   CL,4
  3284.                SHL   BX,CL             ; incremento relativo en bytes
  3285.                XPOP  <DX, CX>
  3286.                RET
  3287. getdmaok       ENDP
  3288.  
  3289. ; ------------ Comprobar si el buffer para el DMA es suficiente, en
  3290. ;              caso de haber un controlador de memoria. Se devuelve
  3291. ;              el código de identificación del controlador en BX, o
  3292. ;              un valor 1234h si no hay controlador; DI indica el
  3293. ;              tamaño de buffer soportado y CF=1 si no basta.
  3294.  
  3295. vds_dma_ok?    PROC
  3296.                XPUSH <AX, CX, DX, SI>
  3297.                CALL  es386?
  3298.                JNE   vds_pse           ; por si las moscas
  3299.                MOV   AX,354Bh
  3300.                PUSH  ES
  3301.                INT   21h               ; ES:BX -> INT 4Bh
  3302.                MOV   AX,ES
  3303.                POP   ES
  3304.                OR    AX,BX
  3305.                JZ    vds_pse           ; INT 4Bh indefinida
  3306.                CMP   AX,0FFFFh
  3307.                JNE   hay_vds?
  3308.                CMP   BX,0FFFFh
  3309.                JE    vds_pse           ; INT 4Bh indefinida
  3310. hay_vds?:      MOV   AX,8102h
  3311.                XOR   DX,DX
  3312.                XOR   SI,SI
  3313.                XOR   DI,DI             ; SI:DI a 0 por si acaso
  3314.                INT   4Bh
  3315.                JC    vds_pse           ; si no hay VDS...
  3316.                MOV   AX,SI
  3317.                OR    AX,DI
  3318.                JZ    vds_pse           ; no parece una VDS...
  3319.                CMP   SI,0
  3320.                JE    dma_s_ok
  3321.                MOV   DI,0FFFFh         ; con 64K nos basta
  3322. dma_s_ok:      CMP   DI,tbuffer
  3323.                JAE   vds_ok
  3324.                STC                     ; no basta el buffer
  3325.                XPOP  <SI, DX, CX, AX>
  3326.                RET
  3327. vds_pse:       MOV   BX,1234h          ; retornar sin problemas
  3328.                MOV   DI,0FFFFh
  3329. vds_ok:        CLC                     ; basta ese buffer
  3330.                XPOP  <SI, DX, CX, AX>
  3331.                RET
  3332. vds_dma_ok?    ENDP
  3333.  
  3334. ; ------------ Adaptar parámetros del programa si ya está instalado.
  3335.  
  3336. adaptar_param  PROC
  3337.                PUSH  ES
  3338.                CMP   instalado,ON
  3339.                JNE   salir_adap        ; aún no instalado
  3340.                MOV   ES,tsr_seg
  3341.                CMP   param_g,ON
  3342.                JNE   param_dr?
  3343.                MOV   AX,gaprw
  3344.                MOV   ES:gaprw,AX
  3345. param_dr?:     CMP   param_dron,ON
  3346.                JNE   param_droff?
  3347.                MOV   ES:drdos6,ON      ; soporte DISKCOPY de DR-DOS
  3348. param_droff?:  CMP   param_droff,ON
  3349.                JNE   param_dwon?
  3350.                MOV   ES:drdos6,OFF
  3351. param_dwon?:   CMP   param_dwon,ON
  3352.                JNE   param_dwoff?
  3353.                MOV   ES:cachewr,ON     ; caché escritura retardada
  3354. param_dwoff?:  CMP   param_dwoff,ON
  3355.                JNE   fin_adap
  3356.                MOV   ES:cachewr,OFF
  3357. fin_adap:      MOV   AX,tbase
  3358.                MOV   ES:tbase,AX       ; actualizar siempre esta cte
  3359. salir_adap:    POP   ES
  3360.                RET
  3361. adaptar_param  ENDP
  3362.  
  3363. ; ------------ Informar de las unidades empleadas y otras cuestiones.
  3364.  
  3365. informe        PROC
  3366.                PUSH  ES
  3367.                MOV   ES,tsr_seg
  3368.                MOV   AL,ES:unidad_base      ; primera letra unidad
  3369.                MOV   BL,ES:info_E.unidad
  3370.                MOV   BH,ES:info_E.tipo_drv  ; datos A:
  3371.                MOV   CL,ES:info_F.unidad
  3372.                MOV   CH,ES:info_F.tipo_drv  ; datos B:
  3373.                POP   ES
  3374.  
  3375.                LEA   DX,hay_2mgui_txt
  3376.                CALL  print
  3377.  
  3378.                MOV   nueva_u,AL
  3379.                ADD   nueva_u,'A'
  3380. informa_otra:  MOV   vieja_u,BL
  3381.                ADD   vieja_u,'A'
  3382.                LEA   DX,hay_en_txt
  3383.                CALL  print
  3384.                LEA   DX,nueva_u        ; indicar nueva unidad
  3385.                CALL  print
  3386.                MOV   BL,BH
  3387.                DEC   BL
  3388.                MOV   BH,0
  3389.                SHL   BX,1
  3390.                ADD   BX,OFFSET t_drvs
  3391.                MOV   DX,[BX]
  3392.                CALL  print             ; imprimir su tipo
  3393.                LEA   DX,hay2_txt
  3394.                CALL  print
  3395.                LEA   DX,vieja_u        
  3396.                CALL  print             ; imprimir letra física
  3397.  
  3398.                AND   CH,CH
  3399.                JZ    fin_informe       ; no hay más unidades
  3400.                MOV   BX,CX
  3401.                MOV   CH,0
  3402.                INC   nueva_u
  3403.                JMP   informa_otra      ; informar 2ª unidad
  3404.  
  3405. fin_informe:   PUSH  ES                ; *
  3406.                MOV   ES,tsr_seg
  3407.                LEA   DX,gap_txt
  3408.                CALL  print
  3409.                MOV   AX,ES:gaprw
  3410.                XOR   DX,DX
  3411.                MOV   CL,3
  3412.                CALL  print_32          ; indicar el GAP
  3413.                LEA   DX,dma1_txt
  3414.                CALL  print
  3415.                CMP   ES:modoDMA,ON
  3416.                JE    modo_dma_ok
  3417.                LEA   DX,dmano_txt
  3418.                CALL  print
  3419. modo_dma_ok:   LEA   DX,dma2_txt
  3420.                CALL  print             ; y el modo DMA
  3421.                CMP   ES:ems_handle,0
  3422.                LEA   DX,buffer_ems_txt
  3423.                JE    modo_ems_ok
  3424.                CALL  print
  3425. modo_ems_ok:   LEA   DX,cache_off_txt
  3426.                CMP   ES:cachewr,ON
  3427.                JE    modo_cache_ok
  3428.                CALL  print
  3429. modo_cache_ok: LEA   DX,sopdr_on_txt
  3430.                CMP   ES:drdos6,ON
  3431.                JNE   modo_dr_ok
  3432.                CALL  print
  3433. modo_dr_ok:    POP   ES                ; *
  3434.                LEA   DX,pet_ayuda_txt
  3435.                CALL  print             ; ... cómo pedir ayuda ...
  3436.                RET
  3437. informe        ENDP
  3438.  
  3439. ; ------------ Formatear disquete 2MGUI.
  3440.  
  3441. format_disk    PROC
  3442.                CALL  get_drv           ; obtener unidad física
  3443.                JNC   fmt_buen_drv
  3444.                OR    errw,MALDRV
  3445.                JMP   rep_fmt
  3446. fmt_buen_drv:  CALL  init_flp          ; preparar áreas de datos
  3447.                CALL  init_boot         ; construir sector de arranque
  3448.                CALL  set_fat_buffer    ; buffer para la FAT
  3449.                JNC   fmt_buena_fat
  3450.                JMP   rep_fmt           ; no hay memoria para la FAT
  3451. fmt_buena_fat: MOV   errw,0
  3452.                MOV   status,0          ; borrar errores previos
  3453.                CALL  print_cabf        ; mensaje de cabecera
  3454.                CMP   param_k,ON
  3455.                JE    format_ya         ; opción /K: evitar pausa
  3456.                LEA   DX,pausaf_txt
  3457.                CALL  print
  3458.                MOV   AH,8
  3459.                INT   21h               ; pedir tecla
  3460.                AND   AL,AL
  3461.                JNZ   esa_tec
  3462.                MOV   AH,8
  3463.                INT   21h               ; tecla de doble código
  3464. esa_tec:       LEA   DX,limpia_txt
  3465.                CALL  print
  3466.                CMP   AL,13
  3467.                JE    format_ya
  3468.                JMP   teclaESC?         ; se pulsó ESC
  3469. format_ya:     STC
  3470.                CALL  reset_drv
  3471.                MOV   [SI].cilindro,0
  3472. fmt_otro_cil:  MOV   [SI].cabezal,0    ; empezar en pista/cabeza 0
  3473. fmt_otro_cab:  MOV   CX,4              ; reintentos
  3474.                JMP   fmt_empieza
  3475. fmt_repite:    CLC
  3476.                CALL  reset_drv
  3477. fmt_empieza:   CALL  test_kb
  3478.                JNC   fmt_proc
  3479.                JMP   teclaESC?
  3480. fmt_proc:      CALL  print_cc          ; imprimir nº cilindro/cabezal
  3481.                CALL  genera_infof
  3482.                CALL  motor_ok
  3483.                CALL  seek_drv
  3484.                LEA   DX,f_txt          ; [F--]
  3485.                CALL  print
  3486.                CALL  formatea_pista
  3487.                CALL  test_err          ; ¿error?
  3488.                JNC   fmt_wr?
  3489.                JMP   rep_fmt
  3490. fmt_wr?:       JNZ   fmt_wr
  3491.                LOOP  fmt_repite        ; reintentos
  3492.                JMP   marca_pista       ; pista defectuosa
  3493. fmt_wr:        CMP   [SI].cilindro,1
  3494.                CMC
  3495.                CALL  init_buffer       ; buffer a 0 en cilindro 0
  3496.                LEA   DX,w_txt
  3497.                CALL  print             ; [-X-]
  3498.                CALL  escribe_pista
  3499.                CALL  fix_err           ; detectar capacidad excesiva
  3500.                CALL  test_err          ; ¿error?
  3501.                JC    rep_fmt
  3502.                JNZ   fmt_vr
  3503.                LOOP  fmt_repite        ; reintentos
  3504.                JMP   marca_pista       ; pista defectuosa
  3505. fmt_vr:        CMP   [SI].cilindro,2
  3506.                JB    si_verificar      ; verificar siempre pistas 0-1
  3507.                CMP   param_n,ON
  3508.                JE    fmt_inc_cab       ; verificación desactivada
  3509. si_verificar:  CALL  test_kb
  3510.                JC    teclaESC?
  3511.                LEA   DX,v_txt
  3512.                CALL  print             ; [--V]
  3513.                CALL  lee_pista
  3514.                CALL  fix_err           ; detectar capacidad excesiva
  3515.                CALL  test_err          ; ¿error?
  3516.                JC    rep_fmt
  3517.                JNZ   fmt_inc_cab
  3518.                LOOP  fmt_repite
  3519.                JMP   marca_pista       ; pista defectuosa
  3520. fmt_inc_cab:   INC   [SI].cabezal
  3521.                CMP   [SI].cabezal,1
  3522.                JA    fmt_inc_cil
  3523.                JMP   fmt_otro_cab      ; a por otro cabezal...
  3524. fmt_inc_cil:   INC   [SI].cilindro
  3525.                MOV   AL,[SI].cilindro
  3526.                CMP   AL,2
  3527.                JB    fmt_lento
  3528.                CMP   param_q,ON
  3529.                JE    fin_fmt           ; opción /Q
  3530. fmt_lento:     CMP   AL,maxpistas
  3531.                JAE   fin_fmt
  3532.                JMP   fmt_otro_cil      ; a por otro cilindro ...
  3533. teclaESC?:     CMP   AX,1000h
  3534.                JE    fin_fmt           ; Quickformat
  3535.                OR    errw,ABORTADO
  3536.                JMP   rep_fmt
  3537. marca_pista:   CMP   [SI].cilindro,0   ; ¿no puede ni con la primera?
  3538.                JE    rep_fmt           ; mal asunto, es la del sistema
  3539.                CALL  marcar_fat
  3540.                JMP   fmt_inc_cab       ; marcar esa pista y a por otra
  3541. fin_fmt:       CALL  init_disk
  3542. rep_fmt:       CLC
  3543.                CALL  motor_off_cnt     ; cuenta normal detención motor
  3544.                CALL  info_fmt
  3545.                TEST  errw,MALDRV OR MUCHAFAT OR ABORTADO
  3546.                JNZ   format_fin        ; fin total del proceso
  3547.                CMP   param_k,ON
  3548.                JE    format_fin        ; con /K sólo un disco
  3549.                JMP   format_disk       ; formatear más discos
  3550. format_fin:    RET
  3551. format_disk    ENDP
  3552.  
  3553. ; ------------ Comprobar si se pulsa ESC y limpiar buffer.
  3554.  
  3555. test_kb        PROC
  3556.                MOV   AH,1
  3557.                INT   16h
  3558.                JZ    no_ESC            ; no quedan teclas en el buffer
  3559.                MOV   AH,0
  3560.                INT   16h
  3561.                CMP   AL,27
  3562.                JE    si_ESC            ; tecla ESC
  3563.                CMP   AX,1000h
  3564.                JE    si_ESC            ; ALT-Q
  3565.                JMP   test_kb
  3566. si_ESC:        STC
  3567.                RET
  3568. no_ESC:        CLC
  3569.                RET
  3570. test_kb        ENDP
  3571.  
  3572. ; ------------ Si da error de unidad no preparada al escribir o al
  3573. ;              verificar en la primera pista y no lo dio al formatear,
  3574. ;              es que se pide más capacidad de la soportada.
  3575.  
  3576. fix_err        PROC
  3577.                TEST  status,80h
  3578.                JZ    fix_err_r
  3579.                CMP   [SI].cilindro,0
  3580.                JNE   fix_err_r         ; si no es cilindro 0, vale
  3581.                MOV   status,7Fh
  3582. fix_err_r:     RET
  3583. fix_err        ENDP
  3584.  
  3585. ; ------------ Comprobar categoría del error. Los errores fatales
  3586. ;              provocan el final inmediato del formateo.
  3587.  
  3588. test_err       PROC
  3589.                CMP   status,0
  3590.                JE    err_none
  3591.                CMP   status,3          ; ¿protegido contra escritura?
  3592.                JE    err_fatal
  3593.                TEST  status,80h        ; ¿no preparada?
  3594.                JNZ   err_fatal
  3595.                CMP   SP,SP
  3596.                CLC
  3597.                RET                     ; ZF=1 y CF=0 -> error "venial"
  3598. err_none:      CMP   SP,0
  3599.                CLC
  3600.                RET                     ; ZF=0 y CF=0 -> sin error
  3601. err_fatal:     CMP   SP,SP
  3602.                STC
  3603.                RET                     ; ZF=1 y CF=1 -> error grave
  3604. test_err       ENDP
  3605.  
  3606. ; ------------ Poner el buffer de pista con valores de test. A la
  3607. ;              entrada, CF=0 selecciona un buffer lleno de ceros
  3608. ;              y CF=1 lleno de una secuencia aleatoria predecible.
  3609.  
  3610. init_buffer    PROC
  3611.                PUSH  ES
  3612.                XPUSH <AX, BX, CX>
  3613.                MOV   ES,sbuffer
  3614.                MOV   BX,0
  3615.                JC    buffer_rnd
  3616.                CALL  tpistaAX
  3617.                MOV   CX,AX
  3618. fill_pis0:     MOV   BYTE PTR ES:[BX],0
  3619.                INC   BX
  3620.                LOOP  fill_pis0         ; buffer a 0
  3621.                JMP   buff_init
  3622. buffer_rnd:    CALL  tpistaAX
  3623.                MOV   CX,AX
  3624.                MOV   semilla,1         ; nº aleatorios predecibles
  3625. fill_pisx:     CALL  rnd
  3626.                MOV   BYTE PTR ES:[BX],AL
  3627.                INC   BX
  3628.                LOOP  fill_pisx         ; buffer con patrón aleatorio
  3629. buff_init:     XPOP  <CX, BX, AX>
  3630.                POP   ES
  3631.                RET
  3632. init_buffer    ENDP
  3633.  
  3634. ; ------------ Imprimir cabecera de formateo.
  3635.  
  3636. print_cabf     PROC
  3637.                XPUSHA
  3638.                LEA   DX,fmtm1_txt
  3639.                CALL  print             ; "Formateando ..."
  3640.                MOV   AL,[SI].infb.mfrontera
  3641.                MOV   AH,0
  3642.                MUL   [SI].infb.tpista1
  3643.                MOV   BX,DX
  3644.                MOV   CX,AX             ; BX:CX bytes hasta FRONTERA
  3645.                MOV   AL,maxpistas
  3646.                SUB   AL,[SI].infb.mfrontera
  3647.                MOV   AH,0
  3648.                MUL   [SI].infb.tpista2 ; DX:AX bytes tras FRONTERA
  3649.                ADD   AX,CX
  3650.                ADC   DX,BX             ; bytes totales por cara
  3651.                MOV   CL,maxpistas
  3652.                MOV   CH,0
  3653.                DIV   CX                ; bytes por pista
  3654.                XOR   DX,DX
  3655.                MOV   CL,7+16
  3656.                PUSH  AX                ; *
  3657.                CALL  print_32          ; imprimir bytes por pista
  3658.                LEA   DX,fmtm2_txt
  3659.                CALL  print
  3660.                MOV   DL,disquetera
  3661.                ADD   DL,'A'
  3662.                MOV   AH,2
  3663.                INT   21h               ; imprimir unidad
  3664.                LEA   DX,fmtm3_txt
  3665.                CALL  print
  3666.                MOV   DL,[SI].unidad
  3667.                CALL  tipo_disco        ; tipo de la unidad
  3668.                DEC   BL
  3669.                MOV   BH,0
  3670.                SHL   BX,1
  3671.                ADD   BX,OFFSET t_drvs
  3672.                MOV   DX,[BX]
  3673.                CALL  print             ; imprimir tipo
  3674.                LEA   DX,fmtm4_txt
  3675.                CALL  print
  3676.                LEA   DX,fmtm5_txt
  3677.                CALL  print
  3678.                CALL  print_dsk_tipo    ; imprimir tipo del disquete
  3679.                LEA   DX,fmtm6_txt
  3680.                CALL  print
  3681.                POP   AX                ; * bytes por pista
  3682.                MOV   BL,maxpistas
  3683.                MOV   BH,0
  3684.                SHL   BX,1              ; pore las dos caras
  3685.                MUL   BX                ; DX:AX bytes en disco
  3686.                MOV   BX,1024
  3687.                DIV   BX                ; AX Kbytes
  3688.                XOR   DX,DX
  3689.                MOV   CL,6+16
  3690.                CALL  print_32          ; imprimir Kbytes
  3691.                LEA   DX,fmtm7_txt
  3692.                CALL  print
  3693.                XPOPA
  3694.                RET
  3695. print_cabf     ENDP
  3696.  
  3697. ; ------------ Imprimir el tipo del disquete en uso.
  3698.  
  3699. print_dsk_tipo PROC
  3700.                MOV   DL,[SI].unidad
  3701.                CALL  tipo_disco        ; tipo de la unidad
  3702.                MOV   BH,BL
  3703.                CMP   BL,5
  3704.                JB    ted_no
  3705.                MOV   BL,4              ; en 2.88M por defecto 1.44M
  3706. ted_no:        MOV   AL,param_dd
  3707.                OR    AL,param_dh
  3708.                CMP   AL,OFF
  3709.                JE    tdd_ok
  3710.                DEC   BL                ; disco DD
  3711. tdd_ok:        CMP   param_ed,ON
  3712.                JNE   ted_ok
  3713.                CMP   BH,5
  3714.                JNE   ted_ok
  3715.                MOV   BL,5              ; disco 2.88M
  3716. ted_ok:        DEC   BL
  3717.                MOV   BH,0
  3718.                SHL   BX,1
  3719.                ADD   BX,OFFSET t_drvs
  3720.                MOV   DX,[BX]
  3721.                CALL  print             ; imprimir tipo
  3722.                RET
  3723. print_dsk_tipo ENDP
  3724.  
  3725. ; ------------ Imprimir nº cilindro y cabezal.
  3726.  
  3727. print_cc       PROC
  3728.                XPUSHA
  3729.                LEA   DX,cil_txt
  3730.                CALL  print
  3731.                MOV   AL,[SI].cilindro
  3732.                CALL  print_8
  3733.                LEA   DX,cab_txt
  3734.                CALL  print
  3735.                MOV   AL,[SI].cabezal
  3736.                CALL  print_8
  3737.                LEA   DX,p_txt
  3738.                CALL  print
  3739.                XPOPA
  3740.                RET
  3741. print_cc       ENDP
  3742.  
  3743. ; ------------ Establecer buffer para la FAT.
  3744.  
  3745. set_fat_buffer PROC
  3746.                MOV   AX,fbuffer
  3747.                AND   AX,AX
  3748.                JNZ   haymemfat         ; ya había memoria asignada
  3749.                MOV   AX,bsectfat
  3750.                MOV   BX,[SI].bytes_sector
  3751.                MUL   BX                ; sectfat * tamaño sector
  3752.                MOV   CL,4
  3753.                SHR   AX,CL             ; bytes -> párrafos
  3754.                MOV   BX,AX
  3755.                MOV   AH,48h
  3756.                PUSH  BX
  3757.                INT   21h               ; pedir memoria
  3758.                POP   BX
  3759.                JNC   haymemfat
  3760.                OR    errw,MUCHAFAT     ; no hay memoria suficiente
  3761.                STC
  3762.                RET
  3763. haymemfat:     MOV   fbuffer,AX
  3764.                PUSH  ES                ; *
  3765.                MOV   ES,AX
  3766.                XOR   DI,DI
  3767.                MOV   AX,bsectfat
  3768.                MUL   [SI].bytes_sector ; sectores -> bytes
  3769.                SHR   AX,1              ; palabras
  3770.                MOV   CX,AX
  3771.                SUB   CX,2              ; saltar dos primeras palabras
  3772.                MOV   AL,media_id
  3773.                CLD
  3774.                STOSB                   ; byte de medios
  3775.                MOV   AX,0FFFFh
  3776.                STOSW                   ; otros dos bytes
  3777.                MOV   AL,0
  3778.                CMP   tipofat,12
  3779.                JE    init_fat4
  3780.                DEC   AL
  3781. init_fat4:     STOSB                   ; 0 (FAT12) ó 0FFh (FAT16)
  3782.                XOR   AX,AX
  3783.                REP   STOSW             ; poner resto de FAT a 0
  3784.                POP   ES                ; *
  3785.                CLC
  3786.                RET
  3787. set_fat_buffer ENDP
  3788.  
  3789. ; ------------ Marcar pista defectuosa en la FAT.
  3790.  
  3791. marcar_fat     PROC
  3792.                MOV   AL,[SI].cilindro
  3793.                SHL   AL,1
  3794.                ADD   AL,[SI].cabezal   ; AX pistas hasta la frontera
  3795.                MOV   AH,0
  3796.                MOV   CX,0              ; CX pistas desde la frontera
  3797.                MOV   BL,[SI].infb.mfrontera
  3798.                SHL   BL,1
  3799.                CMP   AL,BL
  3800.                JBE   dispis_ok
  3801.                MOV   CL,AL
  3802.                MOV   AL,BL             ; hay cruce de frontera
  3803.                SUB   CL,AL
  3804. dispis_ok:     MUL   [SI].infb.tpista1
  3805.                XPUSH <DX, AX>
  3806.                MOV   AX,CX
  3807.                MUL   [SI].infb.tpista2 ; DX:AX = bytes tras frontera
  3808.                XPOP  <BX, CX>          ; CX:BX = bytes antes frontera
  3809.                ADD   AX,BX
  3810.                ADC   DX,CX             ; offset al primer byte erróneo
  3811.                XPUSH <AX, DX>
  3812.                MOV   CX,[SI].bytes_sector
  3813.                DIV   CX
  3814.                MOV   BX,AX             ; BX = primer sector erróneo
  3815.                CALL  tpistaAX
  3816.                MOV   CX,AX             ; tamaño pista
  3817.                XPOP  <DX, AX>
  3818.                ADD   AX,CX
  3819.                ADC   DX,0
  3820.                MOV   CX,[SI].bytes_sector
  3821.                DIV   CX
  3822.                AND   DX,DX
  3823.                JZ    ultserr_ok
  3824.                INC   AX                ; AX = último sector erróneo
  3825. ultserr_ok:    SUB   AX,BX
  3826.                MOV   CL,bscluster
  3827.                MOV   CH,0
  3828.                ADD   AX,CX
  3829.                DEC   AX
  3830.                XOR   DX,DX
  3831.                DIV   CX                ; AX = clusters defectuosos
  3832.                DEC   BX                ; descontar BOOT
  3833.  
  3834.                PUSH  AX
  3835.                MOV   AX,32
  3836.                MUL   brootdir
  3837.                DIV   [SI].bytes_sector
  3838.                SUB   BX,AX             ; descontar ROOT
  3839.                POP   AX
  3840.  
  3841.                MOV   CL,bnfats
  3842.                MOV   CH,0
  3843. desc_fat:      SUB   BX,bsectfat
  3844.                LOOP  desc_fat          ; descontar FAT(s)
  3845.                XCHG  AX,BX             ; AX=primer sector, BX=nºclusters
  3846.                XOR   DX,DX
  3847.                MOV   CL,bscluster
  3848.                DIV   CX                ; AX = primer cluster
  3849.                ADD   AX,2              ; se numeran desde 2
  3850.                MOV   CX,BX
  3851. marcar:        CALL  badpoke_fat       ; marcar cluster erróneo
  3852.                INC   AX
  3853.                LOOP  marcar
  3854.                RET
  3855. marcar_fat     ENDP
  3856.  
  3857.                ; --- Modificar una entrada en la FAT12 ó 16.
  3858.  
  3859. badpoke_fat    PROC
  3860.                XPUSH <DS, AX, BX, CX>
  3861.                MOV   DS,fbuffer
  3862.                XOR   BX,BX
  3863.                CMP   CS:tipofat,16
  3864.                JE    poke_fat16
  3865.                MOV   DX,0FF7h          ; cluster defectuoso
  3866.                CALL  poke_fat12
  3867.                JMP   fat_poked
  3868. poke_fat16:    SHL   AX,1
  3869.                ADD   BX,AX
  3870.                MOV   WORD PTR DS:[BX],0FFF7h
  3871. fat_poked:     XPOP  <CX, BX, AX, DS>
  3872.                RET
  3873. badpoke_fat    ENDP
  3874.  
  3875.                ; --- Escribir un elemento en una FAT-12
  3876.                ;     Entrada: AX    = posición de dicho elemento
  3877.                ;              DS:BX = FAT cargada en memoria
  3878.                ;              DX    = nuevo valor de dicho elemento
  3879.  
  3880. poke_fat12     PROC
  3881.                PUSH  AX                ; preservar registros
  3882.                PUSH  BX
  3883.                PUSH  DX
  3884.                ADD   BX,AX             ; BX = BX + cluster
  3885.                SHR   AX,1              ; AX = cluster / 2
  3886.                PUSHF                   ; CF = 1 si impar
  3887.                ADD   BX,AX             ; BX = BX + cluster * 1,5
  3888.                MOV   AX,[BX]           ; AX = palabra con dato 12 bits
  3889.                POPF
  3890.                JC    poke_fat_imp
  3891.                AND   AX,1111000000000000b  ; preservar la otra entrada
  3892.                JMP   poke_fat_ok
  3893. poke_fat_imp:  AND   AX,0000000000001111b  ; preservar la otra entrada
  3894.                PUSH  CX
  3895.                MOV   CL,4
  3896.                SHL   DX,CL             ; colocarlo: 4 bits a la izda
  3897.                POP   CX
  3898. poke_fat_ok:   OR    AX,DX             ; «mezclar»
  3899.                MOV   [BX],AX           ; nuevo valor en la FAT
  3900.                POP   DX
  3901.                POP   BX
  3902.                POP   AX
  3903.                RET                     ; retorno sin alterar registros
  3904. poke_fat12     ENDP
  3905.  
  3906. ; ------------ Inicializar BOOT y FAT (y ROOT si procede).
  3907.  
  3908. init_disk      PROC
  3909.                XPUSHA
  3910.                MOV   [SI].cilindro,0
  3911.                MOV   [SI].cabezal,0
  3912.                CLC
  3913.                CALL  init_buffer       ; buffer a 0
  3914.                MOV   CX,[SI].bytes_sector
  3915.                XPUSH <ES, SI>          ; *
  3916.                MOV   ES,sbuffer
  3917.                XOR   DI,DI
  3918.                LEA   SI,sector_boot
  3919.                CLD
  3920.                REP   MOVSB             ; crear BOOT
  3921.                XPOP  <SI, ES>          ; *
  3922.                CLC
  3923.                CALL  reset_drv
  3924.                CALL  motor_ok
  3925.                CALL  seek_drv
  3926.                CALL  escribe_pista     ; grabar a bajo nivel el BOOT
  3927.                CMP   status,0
  3928.                JNE   fallo_init
  3929.  
  3930.                PUSH  ES
  3931.                MOV   ES,tsr_seg
  3932.                MOV   ES:[SI].cambiodisco,ON  ; simular cambio de disco
  3933.                POP   ES
  3934.  
  3935.                MOV   DL,disquetera
  3936.                INC   DL
  3937.                MOV   AH,32h
  3938.                PUSH  DS
  3939.                INT   21h               ; forzar acceso a disco usando
  3940.  
  3941.                POP   DS                ; ya el sistema operativo
  3942.                MOV   AL,disquetera
  3943.                XOR   BX,BX
  3944.                MOV   CX,bsectfat       ; sectores en FAT
  3945.                MOV   DX,1
  3946.                PUSH  DS                ; *
  3947.                MOV   DS,fbuffer
  3948.                CALL  int26h            ; grabar FAT1
  3949.                POP   DS                ; *
  3950.                JC    fallo_init        ; fallo al escribir FAT
  3951.                CMP   bnfats,1
  3952.                JE    init_root         ; sólo una FAT (CF=0)
  3953.                XOR   BX,BX
  3954.                MOV   CX,bsectfat
  3955.                MOV   DX,CX
  3956.                INC   DX                ; saltar FAT1 + BOOT
  3957.                MOV   AL,disquetera
  3958.                PUSH  DS                ; *
  3959.                MOV   DS,fbuffer
  3960.                CALL  int26h            ; grabar FAT2
  3961.                POP   DS                ; *
  3962.                JNC   init_root
  3963. fallo_init:    OR    errw,MALSYS       ; fallo en áreas del sistema
  3964.                JMP   fin_init
  3965. init_root:     MOV   BX,ptr_label
  3966.                AND   BX,BX
  3967.                JNZ   tetiq_ok
  3968.                MOV   BX,ptr_ilabel
  3969.                AND   BX,BX
  3970.                JZ    fin_init          ; no hay etiqueta de volúmen
  3971. tetiq_ok:      CLC
  3972.                CALL  init_buffer       ; buffer a 0
  3973.                CALL  copia_etiq
  3974.                CMP   BX,ptr_ilabel
  3975.                JNE   wr_root
  3976.                CALL  inc_etiq
  3977. wr_root:       MOV   CX,bsectfat
  3978.                MOV   AL,bnfats
  3979.                MOV   AH,0
  3980.                MUL   CX
  3981.                INC   AX                ; primer sector directorio raíz
  3982.                MOV   DX,AX
  3983.                MOV   CX,1
  3984.                MOV   AL,disquetera
  3985.                PUSH  DS                ; *
  3986.                MOV   DS,sbuffer
  3987.                XOR   BX,BX
  3988.                CALL  int26h            ; grabar ROOT
  3989.                POP   DS
  3990. fin_init:      XPOPA
  3991.                RET
  3992. init_disk      ENDP
  3993.  
  3994. ; ------------ Como el MS-DOS 7 de Windows 95 (beta 2) no deja usar
  3995. ;              la INT 26h, se graba por IOCTL :-)
  3996.  
  3997. int26h         PROC
  3998.                XPUSHA
  3999.                PUSH  ES
  4000.                MOV   ES,ES:tsr_seg
  4001.                MOV   AH,ES:drdos6
  4002.                MOV   ES:drdos6,OFF          ; anular emulación DR-DOS
  4003.                MOV   SI,1                   ; con caché: CX operaciones
  4004.                CMP   ES:cachewr,ON
  4005.                MOV   SI,CX                  ; sin caché: una operación
  4006.                JE    nsi26ok
  4007. nsi26ok:       POP   ES
  4008. i26_buc:       XPUSH <AX, BX, CX, DX, SI, DS>    ; * (preservar emulacion)
  4009.                LEA   DI,buffer_aux
  4010.                MOV   BYTE PTR ES:[DI],0
  4011.                MOV   WORD PTR ES:[DI+1],0   ; cabezal
  4012.                MOV   WORD PTR ES:[DI+3],DX  ; primer cilindro
  4013.                MOV   WORD PTR ES:[DI+5],0   ; primer sector
  4014.                MOV   WORD PTR ES:[DI+7],SI  ; nº sectores
  4015.                MOV   WORD PTR ES:[DI+9],BX
  4016.                MOV   WORD PTR ES:[DI+11],DS ; dirección
  4017.                INC   AX
  4018.                MOV   BL,AL                  ; unidad
  4019.                MOV   AX,440Dh
  4020.                MOV   CX,841h                ; escribir pista
  4021.                MOV   DX,DI
  4022.                PUSH  ES
  4023.                POP   DS
  4024.                INT   21h
  4025.                XPOP  <DS, SI, DX, CX, BX, AX>    ; *
  4026.                JC    i26_fallo
  4027.                ADD   BX,ES:boot_tsect
  4028.                INC   DX
  4029.                SUB   CX,SI
  4030.                JNZ   i26_buc
  4031.                CLC
  4032. i26_fallo:     PUSH  ES
  4033.                MOV   ES,ES:tsr_seg          ; cuidado con flags :-)
  4034.                MOV   ES:drdos6,AH           ; restaurar emulación DR-DOS
  4035.                POP   ES
  4036.                XPOPA
  4037.                RET
  4038. int26h         ENDP
  4039.  
  4040.                ; --- Crear etiqueta de volúmen (psp:BX -> sbuffer:0)
  4041.  
  4042. copia_etiq     PROC
  4043.                XPUSHA
  4044.                XPUSH <ES, DS>
  4045.                CLD
  4046.                MOV   ES,sbuffer
  4047.                XOR   DI,DI
  4048.                MOV   DS,psp
  4049.                MOV   SI,BX
  4050.                MOV   CX,11
  4051.                JCXZ  nom_et_cp
  4052. genera_et:     LODSB
  4053.                CMP   AL,' '
  4054.                JE    completa_et
  4055.                CMP   AL,9
  4056.                JE    completa_et
  4057.                CMP   AL,'/'
  4058.                JE    completa_et
  4059.                CMP   AL,13
  4060.                JE    completa_et
  4061.                STOSB
  4062.                LOOP  genera_et
  4063.                JMP   nom_et_cp
  4064. completa_et:   MOV   AL,' '
  4065.                STOSB
  4066.                LOOP  completa_et
  4067. nom_et_cp:     MOV   BYTE PTR ES:[11],28h
  4068.                POP   DS
  4069.                MOV   WORD PTR ES:[22],2048  ; 1:00
  4070.                MOV   WORD PTR ES:[24],7745  ; 1/2/95
  4071.                LEA   DX,null
  4072.                MOV   AX,3D00h
  4073.                MOV   CX,0
  4074.                INT   21h               ; abrir fichero "NUL"
  4075.                JC    fin_cpet
  4076.                MOV   BX,AX
  4077.                MOV   AX,5700h
  4078.                PUSH  BX
  4079.                INT   21h               ; consultar su fecha/hora
  4080.                POP   BX
  4081.                JC    fin_cpetcf
  4082.                MOV   AX,CX
  4083.                OR    AX,DX
  4084.                JZ    fin_cpetcf
  4085.                MOV   WORD PTR ES:[22],CX    ; hora
  4086.                MOV   WORD PTR ES:[24],DX    ; fecha
  4087. fin_cpetcf:    MOV   AX,3E00h
  4088.                INT   21h               ; cerrar fichero "NUL"
  4089. fin_cpet:      POP   ES
  4090.                XPOPA
  4091.                RET
  4092. copia_etiq     ENDP
  4093.  
  4094.                ; --- Incrementar nº de etiqueta de volúmen.
  4095.  
  4096. inc_etiq       PROC
  4097.                PUSH  DS
  4098.                MOV   DS,psp
  4099.                MOV   CX,16
  4100. busca_fetq:    MOV   AL,[BX]
  4101.                CMP   AL,' '
  4102.                JE    fin_etq
  4103.                CMP   AL,9
  4104.                JE    fin_etq
  4105.                CMP   AL,'/'
  4106.                JE    fin_etq
  4107.                CMP   AL,13
  4108.                JE    fin_etq
  4109.                INC   BX
  4110.                LOOP  busca_fetq
  4111.                JMP   etq_inc
  4112. fin_etq:       DEC   BX
  4113.                MOV   AL,[BX]
  4114.                CMP   AL,'0'
  4115.                JB    etq_inc
  4116.                CMP   AL,'9'
  4117.                JA    etq_inc
  4118.                INC   AL
  4119.                CMP   AL,'9'
  4120.                JA    etq_p10
  4121.                MOV   [BX],AL
  4122.                JMP   etq_inc
  4123. etq_p10:       MOV   BYTE PTR [BX],'0'
  4124.                JMP   fin_etq
  4125. etq_inc:       POP   DS
  4126.                RET
  4127. inc_etiq       ENDP
  4128.  
  4129. ; ------------ Inicializar sector de arranque.
  4130.  
  4131. init_boot      PROC
  4132.                MOV   AL,[SI].infb.vunidad2
  4133.                MOV   bootp.vunidad2,AL
  4134.                MOV   AH,frontera    ; disco dividido en dos mitades
  4135.                CMP   AL,[SI].vunidad1
  4136.                JNE   init_fr
  4137.                MOV   AH,maxpistas   ; disco uniforme
  4138. init_fr:       MOV   bootp.mfrontera,AH
  4139.                MOV   [SI].infb.mfrontera,AH
  4140.                MOV   AX,bsectini
  4141.                MOV   boot_tsect,AX  ; tamaño de sector usado
  4142.                MOV   AX,tcluster
  4143.                XOR   DX,DX
  4144.                DIV   boot_tsect
  4145.                AND   AL,AL
  4146.                JNZ   init_sc
  4147.                INC   AL
  4148. init_sc:       MOV   bscluster,AL   ; sectores por cluster
  4149.                MOV   AL,nfats
  4150.                MOV   bnfats,AL      ; número de FATs
  4151.  
  4152.                MOV   AX,32
  4153.                MUL   rootdir
  4154.                DIV   boot_tsect
  4155.                AND   DX,DX
  4156.                JZ    bdir_ok
  4157.                INC   AX
  4158. bdir_ok:       MOV   srootdir,AX    ; entradas raíz llenando sectores
  4159.                MUL   boot_tsect
  4160.                MOV   CX,32
  4161.                DIV   CX
  4162.                MOV   brootdir,AX    ; nº entradas ajustado
  4163.  
  4164.                MOV   AX,[SI].infb.tpista2
  4165.                MOV   bootp.tpista2,AX
  4166.                MOV   AX,[SI].infb.tpista1
  4167.                MOV   bootp.tpista1,AX
  4168.                MOV   BL,bootp.mfrontera
  4169.                MOV   BH,0
  4170.                SHL   BX,1
  4171.                MUL   BX
  4172.                MOV   CX,DX
  4173.                MOV   BX,AX          ; CX:BX bytes primera parte disco
  4174.                MOV   AL,maxpistas
  4175.                SUB   AL,[SI].infb.mfrontera
  4176.                MOV   AH,0
  4177.                SHL   AX,1
  4178.                MUL   bootp.tpista2  ; DX:AX bytes segunda parte disco
  4179.                ADD   AX,BX
  4180.                ADC   DX,CX          ; DX:AX bytes totales en el disco
  4181.                DIV   boot_tsect
  4182.                MOV   bsectores,AX   ; AX = número de sectores
  4183.  
  4184.                DEC   AX             ; calcular FAT...
  4185.                SUB   AX,srootdir    ; AX = sect tot - 1 boot - N raíz
  4186.                MOV   CX,AX
  4187.                MOV   AL,bscluster
  4188.                MOV   AH,0
  4189.                SHL   AX,1
  4190.                MUL   boot_tsect     ; bytes_sect * sect_cluster * 2
  4191.                MOV   BX,3           ; 1.5 * 2 = 3 (FAT12)
  4192.                DIV   BX
  4193.                ADD   AL,bnfats
  4194.                ADC   AH,0
  4195.                XCHG  AX,CX
  4196.                XOR   DX,DX
  4197.                DIV   CX             ; AX = sectores ocupados por FAT12
  4198.                AND   DX,DX
  4199.                JZ    f12_ok
  4200.                INC   AX
  4201. f12_ok:        MOV   bsectfat,AX    ; sectores en FAT12
  4202.                MOV   tipofat,12     ; supuesta FAT-12
  4203.                ADD   AX,srootdir
  4204.                INC   AX
  4205.                SUB   AX,bsectores   ; (fat+root+1) - sectores totales
  4206.                NEG   AX             ; resta al revés
  4207.                XOR   DX,DX
  4208.                MOV   CL,bscluster
  4209.                MOV   CH,0
  4210.                DIV   CX             ; AX = nº clusters
  4211.                CMP   AX,4085
  4212.                JB    boot_dir       ; en efecto, la FAT es de 12
  4213.  
  4214.                MOV   AX,bsectores
  4215.                DEC   AX             ; calcular FAT...
  4216.                SUB   AX,srootdir    ; AX = sect tot - 1 boot - N raíz
  4217.                MOV   CX,AX
  4218.                MOV   AL,bscluster
  4219.                MOV   AH,0
  4220.                SHL   AX,1
  4221.                MUL   boot_tsect     ; bytes_sect * sect_cluster * 2
  4222.                MOV   BX,4           ; 2 * 2 = 4 (FAT16)
  4223.                DIV   BX
  4224.                ADD   AL,bnfats
  4225.                ADC   AH,0
  4226.                XCHG  AX,CX
  4227.                XOR   DX,DX
  4228.                DIV   CX             ; AX = sectores ocupados por FAT12
  4229.                AND   DX,DX
  4230.                JZ    f16_ok
  4231.                INC   AX
  4232. f16_ok:        MOV   bsectfat,AX    ; sectores en FAT16
  4233.                MOV   tipofat,16
  4234.                MOV   BYTE PTR ftipo+4,'6'
  4235. boot_dir:      MOV   AL,bnfats
  4236.                MOV   AH,0
  4237.                MUL   bsectfat       ; sectores ocupados por FATs
  4238.                INC   AX             ; más BOOT
  4239.                ADD   AX,srootdir    ; más ROOT
  4240.                SUB   AX,bsectores
  4241.                NEG   AX             ; sectores totales - ocupados
  4242.                MOV   BL,bscluster
  4243.                MOV   BH,0
  4244.                XOR   DX,DX
  4245.                DIV   BX             ; DX = sectores redundantes
  4246.                MOV   AX,boot_tsect
  4247.                MUL   DX
  4248.                MOV   BX,32
  4249.                DIV   BX
  4250.                ADD   brootdir,AX    ; aprovecharlos para engordar ROOT
  4251.                CMP   brootdir,240
  4252.                JBE   boot_ok
  4253.                MOV   brootdir,240   ; pero sin pasarse
  4254. boot_ok:       CALL  rnd
  4255.                MOV   WORD PTR bserie,AX     ; inicializar nº serie
  4256.                CALL  rnd
  4257.                MOV   WORD PTR bserie+2,AX
  4258.                RET
  4259. init_boot      ENDP
  4260.  
  4261. ; ------------ Informe del formateo.
  4262.  
  4263. info_fmt       PROC
  4264.                CALL  pr_error          ; posible mensaje de error
  4265.                JNC   cont_info_fmt
  4266.                RET
  4267. cont_info_fmt: LEA   DX,capacidad1_txt
  4268.                CALL  print
  4269.                MOV   AX,bsectores
  4270.                MOV   CX,[SI].bytes_sector
  4271.                MUL   CX
  4272.                MOV   CL,10+16
  4273.                CALL  print_32          ; capacidad cruda en bytes
  4274.                LEA   DX,capacidad2_txt
  4275.                CALL  print
  4276.                MOV   AX,ptr_label
  4277.                OR    AX,ptr_ilabel
  4278.                JZ    no_etiq
  4279.                LEA   DX,etiq_txt
  4280.                CALL  print
  4281.                MOV   CX,11
  4282.                XOR   BX,BX
  4283.                PUSH  DS
  4284.                MOV   DS,sbuffer
  4285. pr_etq:        MOV   AH,2
  4286.                MOV   DL,[BX]
  4287.                XPUSH <BX, CX>
  4288.                INT   21h
  4289.                XPOP  <CX, BX>
  4290.                INC   BX
  4291.                LOOP  pr_etq
  4292.                POP   DS
  4293.                LEA   DX,crlf_txt
  4294.                CALL  print
  4295. no_etiq:       MOV   AX,brootdir
  4296.                XOR   DX,DX
  4297.                MOV   CL,11+16
  4298.                CALL  print_32          ; entradas en directorio raíz
  4299.                LEA   DX,if1_txt
  4300.                CALL  print
  4301.                MOV   AH,36h
  4302.                MOV   DL,disquetera
  4303.                INC   DL
  4304.                INT   21h               ; obtener espacio en disco
  4305.                CMP   AX,-1
  4306.                JNE   info_espacio
  4307.                LEA   DX,err_info_txt
  4308.                CALL  print
  4309.                RET
  4310. info_espacio:  XPUSH <AX, BX, CX, DX>
  4311.                MOV   AX,DX
  4312.                XOR   DX,DX
  4313.                MOV   CL,11+16
  4314.                CALL  print_32          ; número de clusters
  4315.                LEA   DX,if2_txt
  4316.                CALL  print
  4317.                XPOP  <DX, CX, BX, AX>
  4318.                XPUSH <AX, BX, CX, DX>
  4319.                MUL   CX
  4320.                MOV   CL,11+16
  4321.                CALL  print_32          ; bytes por cluster
  4322.                LEA   DX,if3_txt
  4323.                CALL  print
  4324.                XPOP  <DX, CX, BX, AX>
  4325.                XPUSH <AX, BX, CX, DX>
  4326.                MOV   BX,DX
  4327.                MUL   CX
  4328.                MUL   BX
  4329.                MOV   CL,11+16
  4330.                CALL  print_32          ; bytes totales
  4331.                LEA   DX,if4_txt
  4332.                CALL  print
  4333.                XPOP  <DX, CX, BX, AX>
  4334.                XPUSH <AX, BX, CX, DX>
  4335.                SUB   DX,BX
  4336.                MOV   BX,DX
  4337.                MUL   CX
  4338.                MUL   BX
  4339.                MOV   CL,11+16
  4340.                CALL  print_32          ; bytes defectuosos
  4341.                LEA   DX,if5_txt
  4342.                CALL  print
  4343.                XPOP  <DX, CX, BX, AX>
  4344.                MUL   CX
  4345.                MUL   BX
  4346.                MOV   CL,11+16
  4347.                CALL  print_32          ; bytes libres
  4348.                LEA   DX,if6_txt
  4349.                CALL  print
  4350.                RET
  4351. info_fmt       ENDP
  4352.  
  4353. ; ------------ Imprimir errores de trabajo.
  4354.  
  4355. pr_error       PROC
  4356.                LEA   DX,limpia_txt
  4357.                CALL  print
  4358.                CALL  get_err_crit
  4359.                TEST  errw,0FFFFh
  4360.                JNZ   errorfmt
  4361.                CLC                     ; no hubo error
  4362.                RET
  4363. errorfmt:      LEA   DX,no_2mgui_txt
  4364.                TEST  errw,MALDRV
  4365.                JZ    errorfmt2?
  4366.                CALL  print             ; la unidad no es 2MGUI
  4367. errorfmt2?:    LEA   DX,abortado_txt
  4368.                TEST  errw,ABORTADO
  4369.                JZ    errorfmt3?
  4370.                CALL  print             ; formateo abortado
  4371. errorfmt3?:    LEA   DX,no_prep_txt
  4372.                TEST  errw,NOPREP
  4373.                JZ    errorfmt4?
  4374.                CALL  print             ; unidad no preparada
  4375. errorfmt4?:    LEA   DX,err_prot_txt
  4376.                TEST  errw,PROTESCR
  4377.                JZ    errorfmt5?
  4378.                CALL  print             ; protegida contra escritura
  4379. errorfmt5?:    LEA   DX,mal_dens_txt
  4380.                TEST  errw,MALADENS
  4381.                JZ    errorfmt6?
  4382.                CALL  print             ; densidad incorrecta
  4383. errorfmt6?:    LEA   DX,mal_sys_txt
  4384.                TEST  errw,MALSYS
  4385.                JZ    errorfmt7?
  4386.                CALL  print             ; fallo en áreas del sistema
  4387. errorfmt7?:    LEA   DX,mucha_fat_txt
  4388.                TEST  errw,MUCHAFAT
  4389.                JZ    errorfmt8?
  4390.                CALL  print             ; FAT demasiado grande
  4391. errorfmt8?:    LEA   DX,mucha_pis_txt
  4392.                TEST  errw,MUCHAPISTA
  4393.                JZ    errorfmt9?
  4394.                CALL  print             ; tamaño de pista no soportado
  4395. errorfmt9?:    STC                     ; hubo error
  4396.                RET
  4397. pr_error       ENDP
  4398.  
  4399. ; ------------ Obtener error fatal.
  4400.  
  4401. get_err_crit   PROC
  4402.                CMP   status,0
  4403.                JNE   hay_crit?
  4404.                RET
  4405. hay_crit?:     MOV   AX,NOPREP
  4406.                TEST  status,80h
  4407.                JZ    err2?
  4408.                OR    errw,AX           ; unidad no preparada
  4409.                RET
  4410. err2?:         MOV   AX,PROTESCR
  4411.                CMP   status,3
  4412.                JNE   err7f?
  4413.                OR    errw,AX           ; protegida contra escritura
  4414.                RET
  4415. err7f?:        MOV   AX,MUCHAPISTA
  4416.                CMP   status,7Fh
  4417.                JNE   err3
  4418.                OR    errw,AX           ; tamaño de pista no soportado
  4419.                RET
  4420. err3:          OR    errw,MALADENS     ; otro caso: mala densidad
  4421.                RET
  4422. get_err_crit   ENDP
  4423.  
  4424. ; ------------ Test de capacidad máxima soportada y velocidad de
  4425. ;              rotación.
  4426.  
  4427. test_disk      PROC
  4428.                CALL  get_drv
  4429.                CALL  init_flp          ; preparar áreas de datos
  4430.  
  4431.                MOV   gaprw,-1          ; rutinas E/S en modo test
  4432.                MOV   [SI].infb.mfrontera,86
  4433.  
  4434.                LEA   DX,test_txt1
  4435.                CALL  print
  4436.                LEA   DX,lin_txt
  4437.                CALL  print             ; mensajes de cabecera
  4438.                MOV   AL,[SI].unidad
  4439.                CALL  drvfloppy?
  4440.                JNC   test_drvok
  4441.                LEA   DX,mal_unidad_txt
  4442.                CALL  print
  4443.                JMP   test_ret          ; unidad incorrecta
  4444. test_drvok:    CMP   param_dh,ON
  4445.                JNE   test_drvAL
  4446.                LEA   DX,dh_test_txt
  4447.                CALL  print
  4448.                JMP   test_ret          ; parámetro /DH en test
  4449. test_drvAL:    CMP   param_nodma,OFF
  4450.                JE    test_posible
  4451.                CMP   pcxt,OFF
  4452.                JE    test_posible
  4453.                LEA   DX,errxtdma_txt
  4454.                CALL  print
  4455.                JMP   test_ret          ; PC/XT: sólo vale con DMA
  4456. test_posible:  LEA   DX,test_txt_t
  4457.                CALL  print
  4458.                MOV   AH,0
  4459.                INT   16h               ; pausa inicial
  4460.                LEA   DX,limpia_txt
  4461.                CALL  print
  4462.                CMP   AL,27
  4463.                JNE   hacer_test
  4464. test_esc:      LEA   DX,limpia_txt     ; cancelado con ESC
  4465.                CALL  print
  4466.                LEA   DX,test_esc_txt
  4467.                CALL  print
  4468.                JMP   test_ret
  4469. hacer_test:
  4470.                MOV   modoDMA,ON        ; supuesto con DMA
  4471.                CMP   param_nodma,ON
  4472.                JNE   haz_test
  4473.                MOV   modoDMA,OFF       ; pues es sin él
  4474.  
  4475.                MOV   tmodo,0           ; primer test con bits iguales
  4476.  
  4477. haz_test:      CMP   modoDMA,OFF
  4478.                JE    aviso_sincero
  4479.                CALL  vds_dma_ok?
  4480.                MOV   AX,14*1024        ; buffer DMA para 1.44M
  4481.                CMP   [SI].tsector,7
  4482.                JE    tdok
  4483.                MOV   AX,28*1024        ; buffer DMA para 2.88M
  4484. tdok:          CMP   DI,AX
  4485.                JAE   otro_test
  4486.                LEA   DX,test_bdma_txt
  4487.                CALL  print
  4488.                JMP   otro_test
  4489.  
  4490. aviso_sincero: LEA   DX,test_dma_txt
  4491.                CALL  print
  4492.  
  4493. otro_test:     CALL  test_pista
  4494.                JC    test_fatal        ; fallo grave (protegido, etc).
  4495.                CMP   status,1
  4496.                JNE   test_prosigue     ; no hay tecla ESC
  4497.                LEA   DX,limpia_txt     ; cancelado con ESC
  4498.                CALL  print
  4499.                LEA   DX,test_esc_txt
  4500.                CALL  print
  4501.                JMP   ret_cam_test
  4502.  
  4503. test_prosigue: CMP   status,2
  4504.                JNE   test_info
  4505.                CALL  pr_error          ; mala densidad
  4506.                JMP   ret_cam_test
  4507. test_fatal:    CALL  pr_error          ; imprimir error trágico
  4508.                JMP   ret_cam_test
  4509. test_info:     LEA   DX,limpia_txt
  4510.                CALL  print
  4511.                LEA   DX,test_r_txt11c  ; información de resultados
  4512.                CMP   modoDMA,ON
  4513.                JE    tif1
  4514.                LEA   DX,test_r_txt11s
  4515. tif1:          CALL  print             ; con/sin DMA
  4516.                LEA   DX,test_r_txt12
  4517.                CALL  print
  4518.                LEA   DX,test_r_txt12i
  4519.                CMP   tmodo,0
  4520.                JE    tif2
  4521.                LEA   DX,test_r_txt12d
  4522. tif2:          CALL  print             ; bits idénticos/aleatorios
  4523.                LEA   DX,test_r_txt13
  4524.                CALL  print
  4525.                MOV   AX,bytes_ok
  4526.                SUB   AX,SYSBYTES
  4527.                XOR   DX,DX
  4528.                MOV   CL,6+16
  4529.                CALL  print_32          ; bytes soportados
  4530.                LEA   DX,test_r_txt14
  4531.                CALL  print
  4532.                CMP   AX,[SI].infb.tpista2
  4533.                JAE   pr_test_res
  4534.                CMP   modoDMA,OFF
  4535.                JE    pr_test_res       ; no decir bobadas en NO-DMA
  4536.  
  4537.                PUSH  AX
  4538.                MOV   AX,243
  4539.                MUL   [SI].infb.tpista2
  4540.                MOV   DH,AH
  4541.                XCHG  DH,DL             ; DX = 95% de tpista2
  4542.                POP   AX
  4543.  
  4544.                CMP   AX,DX
  4545.                JAE   info_maldrv       ; diferencia modesta
  4546.                LEA   DX,disco_def_txt
  4547.                CALL  print             ; ¡lo que casca es el disco!
  4548.                JMP   gap_bien
  4549.  
  4550. info_maldrv:   LEA   DX,test_res_mal
  4551.                CALL  print             ; unidad pésima
  4552. pr_test_res:   LEA   DX,test_r_txt15
  4553.                CALL  print
  4554.                MOV   AX,bytes_max
  4555.                SUB   AX,bytes_ok
  4556.                XOR   DX,DX
  4557.                MOV   CL,6+16
  4558.                CALL  print_32          ; imprimir GAP mínimo
  4559.                LEA   DX,test_r_txt14
  4560.                CALL  print
  4561.  
  4562.                CMP   AX,GAPDEF
  4563.                JBE   gap_bien
  4564.                CMP   AX,255
  4565.                JA    gap_bien          ; no decir bobadas si es raro
  4566.                CMP   modoDMA,OFF
  4567.                JE    gap_bien          ; no decir bobadas en NO-DMA
  4568.                LEA   DX,aviso_gap_txt
  4569.                CALL  print
  4570.  
  4571. gap_bien:      INC   tmodo
  4572.                CMP   tmodo,1
  4573.                JA    no_mas_test
  4574.                JMP   otro_test         ; test con bits aleatorios
  4575.  
  4576. no_mas_test:   LEA   DX,test_res_txt3
  4577.                CALL  print
  4578.                CALL  spin_disk         ; velocidad rotación
  4579. ret_cam_test:  CMP   instalado,ON
  4580.                JNE   test_ret_cam      ; programa no residente
  4581.                PUSH  ES
  4582.                MOV   ES,tsr_seg
  4583.                MOV   ES:[SI].controldrv,ON
  4584.                MOV   ES:[SI].cambiodisco,ON  ; simular cambio de disco
  4585.                POP   ES
  4586. test_ret_cam:  CMP   status,3
  4587.                JE    test_ret          ; salvo protegido de escritura...
  4588.                TEST  status,80h
  4589.                JNZ   test_ret          ; o unidad no preparada...
  4590.                LEA   DX,disco_mal_txt
  4591.                CALL  print             ; recordar disco dañado
  4592. test_ret:      CLC
  4593.                CALL  motor_off_cnt     ; cuenta normal detención motor
  4594.                RET
  4595. test_disk      ENDP
  4596.  
  4597.                ; --- Determinar la capacidad de la pista.
  4598.  
  4599. test_pista     PROC
  4600.                MOV   bytes_ok,0        ; supuesto ninguno
  4601.                MOV   AX,tpistamax1
  4602.                SHL   AX,1              ; AX = tpistamax1 * 2
  4603.                MOV   tmax,AX
  4604.                MOV   CL,3
  4605.                SHR   AX,CL             ; AX = tpistamax1 / 4
  4606.                ADD   tmax,AX           ; máximo posible (tmax+tmin)/2
  4607.                MOV   tmin,0            ; mínimo posible
  4608.                MOV   iter,16           ; como mucho, 16 test
  4609.                STC
  4610.                CALL  reset_drv
  4611. nuevo_test:    CALL  test_kb
  4612.                JNC   test_proc
  4613.                JMP   test_abortado     ; se pulsó ESC
  4614. test_proc:     MOV   status,0
  4615.                MOV   [SI].cilindro,0
  4616.                MOV   [SI].cabezal,0
  4617.                LEA   DX,test_txt2
  4618.                CALL  print             ; mensaje de "Probando..."
  4619.                MOV   AX,tmax
  4620.                ADD   AX,tmin
  4621.                SHR   AX,1
  4622.                MOV   [SI].infb.tpista1,AX   ; tamaño de prueba
  4623.                CMP   AX,1500
  4624.                JAE   test_cont
  4625.                JMP   test_mal_dens     ; aquí pasa algo raro
  4626. test_cont:     CALL  info_bytes
  4627.                CALL  motor_ok
  4628.                CALL  seek_drv
  4629.                CALL  genera_infof
  4630.                CALL  formatea_pista    ; 1º intento formateo
  4631.                CMP   status,0
  4632.                JE    test_wr
  4633.                CALL  formatea_pista    ; 2º intento formateo
  4634.                CMP   status,0
  4635.                JNE   fallo_test
  4636. test_wr:       CMP   tmodo,1
  4637.                CMC                     ; CF==0 si tmodo==0
  4638.                CALL  init_buffer
  4639.                CALL  escribe_pista     ; 1º intento escritura
  4640.                CMP   status,0
  4641.                JE    test_rd
  4642.                CALL  escribe_pista     ; 2º intento escritura
  4643.                CMP   status,0
  4644.                JNE   fallo_test
  4645. test_rd:       CMP   tmodo,1           ; CF==1 si tmodo==0
  4646.                CALL  init_buffer
  4647.                CALL  lee_pista         ; 1º intento lectura
  4648.                CALL  cnt_pista
  4649.                CMP   status,0
  4650.                JE    exito_test
  4651.                CMP   tmodo,1           ; CF==1 si tmodo==0
  4652.                CALL  init_buffer
  4653.                CALL  lee_pista         ; 2º intento lectura
  4654.                CALL  cnt_pista
  4655.                CMP   status,0
  4656.                JNE   fallo_test
  4657. exito_test:    MOV   AX,[SI].infb.tpista1   ; funcionó...
  4658.                MOV   bytes_max,AX
  4659.                MOV   AX,tmax
  4660.                ADD   AX,tmin
  4661.                SHR   AX,1
  4662.                MOV   tmin,AX           ; ...subir límite mínimo
  4663.                JMP   nuevo_test?
  4664. fallo_test:    CALL  test_err          ; falló...
  4665.                JC    aborta_test       ; fallo grave
  4666.                MOV   AX,tmax
  4667.                ADD   AX,tmin
  4668.                SHR   AX,1
  4669.                MOV   tmax,AX           ; ...bajar límite máximo
  4670. nuevo_test?:   MOV   status,0          ; borrar errores anteriores
  4671.                MOV   AX,tmax
  4672.                CMP   AX,tmin
  4673.                JBE   exit_test
  4674.                DEC   iter              ; contador de intentos
  4675.                JZ    exit_test
  4676.                JMP   nuevo_test
  4677. test_abortado: MOV   status,1          ; indicar test abortado
  4678.                JMP   exit_test
  4679. test_mal_dens: MOV   status,2          ; probablemente mala densidad
  4680. exit_test:     CLC
  4681.                RET
  4682. aborta_test:   STC
  4683.                RET
  4684. test_pista     ENDP
  4685.  
  4686.                ; --- Comprobar qué parte de la pista se ha leído bien.
  4687.  
  4688. cnt_pista      PROC
  4689.                XPUSH <ES, AX, BX, CX>
  4690.                MOV   ES,sbuffer
  4691.                XOR   BX,BX
  4692.                MOV   CX,[SI].infb.tpista1
  4693.                CMP   tmodo,0
  4694.                JE    test0
  4695.                MOV   semilla,1         ; bits aleatorios
  4696. testx:         CALL  rnd               ; nº "aleatorio" esperado
  4697.                CMP   ES:[BX],AL
  4698.                JNE   test_rt
  4699.                INC   BX
  4700.                LOOP  testx             ; comprobar cuántos coinciden
  4701.                JMP   test_rt
  4702. test0:         CMP   BYTE PTR ES:[BX],0  ; bits idénticos
  4703.                JNE   test_rt
  4704.                INC   BX
  4705.                LOOP  test0             ; comprobar cuántos coinciden
  4706. test_rt:       MOV   AX,[SI].infb.tpista1
  4707.                SHR   AX,1
  4708.                CMP   CX,AX
  4709.                JA    test_mal          ; ni media pista bien leída
  4710.                MOV   AX,[SI].infb.tpista1
  4711.                SUB   AX,CX
  4712.                MOV   bytes_ok,AX       ; los que se han leído bien
  4713.                MOV   status,0
  4714.                CLC
  4715.                JMP   pista_tr
  4716. test_mal:      MOV   status,2          ; necesaria al menos 1/2 pista
  4717.                STC
  4718. pista_tr:      XPOP  <CX, BX, AX, ES>
  4719.                RET
  4720. cnt_pista      ENDP
  4721.  
  4722.                ; --- Informar de la capacidad en fase de test. A la
  4723.                ;     entrada, AX = bytes por pista en prueba.
  4724.  
  4725. info_bytes     PROC
  4726.                XOR   DX,DX
  4727.                MOV   CL,6+16
  4728.                CALL  print_32          ; capacidad en pruebas
  4729.                LEA   DX,test_txt3
  4730.                CALL  print
  4731.                MOV   DL,disquetera
  4732.                ADD   DL,'A'
  4733.                MOV   AH,2
  4734.                INT   21h               ; imprimir unidad
  4735.                LEA   DX,test_txt4
  4736.                CALL  print
  4737.                CALL  print_dsk_tipo    ; imprimir su tipo
  4738.                LEA   DX,test_txt5
  4739.                CALL  print             ; códigos de retroceso
  4740.                RET
  4741. info_bytes     ENDP
  4742.  
  4743.                ; --- Calcular e imprimir la velocidad de rotación.
  4744.  
  4745. spin_disk      PROC
  4746.                PUSH  ES
  4747.                MOV   ES,sbuffer
  4748.                XOR   DI,DI
  4749.                MOV   BYTE PTR ES:[DI],1     ; 1 sector
  4750.                MOV   BYTE PTR ES:[DI+1],2   ; de 512 bytes
  4751.                MOV   BYTE PTR ES:[DI+2],0   ; cilindro 0
  4752.                MOV   BYTE PTR ES:[DI+3],0   ; cabezal 0
  4753.                MOV   BYTE PTR ES:[DI+4],0   ; sector 0
  4754.                MOV   BYTE PTR ES:[DI+5],2   ; 512 bytes
  4755.                POP   ES
  4756.                CLC
  4757.                CALL  reset_drv
  4758.                CALL  motor_ok
  4759.                CALL  seek_drv
  4760.                CALL  formatea_pista    ; pista de pruebas
  4761.                CLC
  4762.                CALL  reset_drv
  4763.                CALL  motor_ok
  4764.                CALL  seek_drv
  4765.                PUSH  DS                ; *
  4766.                MOV   AX,350Eh
  4767.                INT   21h
  4768.                XPUSH <ES, BX>          ; ** preservar INT 0Eh
  4769.                LEA   DX,nueva_int23
  4770.                MOV   AX,2523h
  4771.                INT   21h               ; establecer nueva INT 23h
  4772.                LEA   DX,nueva_irq6     ; (para evitar Ctrl-Break)
  4773.                MOV   AX,250Eh
  4774.                INT   21h               ; establecer nueva INT 0Eh
  4775.  
  4776.                IN    AL,61h
  4777.                AND   AL,0FDh           ; inhibir sonido
  4778.                OR    AL,1
  4779.                OUT   61h,AL
  4780.                MOV   AL,10110100b
  4781.                OUT   43h,AL            ; 8254: cnt2 byte bajo/alto
  4782.                MOV   AL,0FFh
  4783.                DELAY
  4784.                OUT   42h,AL
  4785.                DELAY
  4786.                OUT   42h,AL            ; cuenta 65535
  4787.                MOV   cnt_l,0FFFFh
  4788.                MOV   cnt_h,0
  4789.  
  4790.                LEA   DX,spin0_txt
  4791.                CALL  print             ; cabecera
  4792.  
  4793.                MOV   iter,0            ; prueba en curso
  4794.  
  4795. repite_spin:   CMP   iter,10
  4796.                JBE   calc_spin         ; como mínimo, 10 test
  4797.                CALL  test_kb
  4798.                JNC   calc_spin
  4799.                JMP   fin_spin
  4800. calc_spin:     MOV   AL,01001010b      ; comando de lectura de ID's
  4801.                CALL  fdc_write
  4802.                JNC   spin_b1
  4803.                JMP   err_spin
  4804. spin_b1:       MOV   AL,[SI].unidad
  4805.                MOV   irq6,OFF          ; bajar flag de interrupción
  4806.                CALL  fdc_write         ; byte 1 de la orden
  4807.  
  4808.                STC
  4809.                CALL  motor_off_cnt     ; evitar que se pare el motor
  4810.  
  4811.                CMP   iter,4
  4812.                JB    calc_rot          ; no imprimir 4 primeros test
  4813.                LEA   DX,spin1_txt
  4814.                CALL  print
  4815.                PUSH  SI                ; *
  4816.                MOV   SI,dif_l
  4817.                MOV   DI,dif_h
  4818.                MOV   AX,25000
  4819.                CALL  mult32x16         ; resultado en DXDISI
  4820.                MOV   AX,29829
  4821.                CALL  divi48x15         ; 25000 / 29829 =
  4822.                XOR   DX,DX             ; = (1/1193180) * 1000000
  4823.                MOV   AX,iter
  4824.                SUB   AX,3              ; nº iteraciones efectivas
  4825.                CALL  divi48x15
  4826.                MOV   DX,DI
  4827.                MOV   AX,SI
  4828.                POP   SI                ; *
  4829.                MOV   cntms_h,DX
  4830.                MOV   cntms_l,AX
  4831.                MOV   CL,01100111b
  4832.                CALL  print_32          ; imprimir milisegundos
  4833.                LEA   DX,spin2_txt
  4834.                CALL  print
  4835.                MOV   AX,iter
  4836.                XOR   DX,DX
  4837.                MOV   CL,4
  4838.                CALL  print_32          ; imprimir iteraciones
  4839.                LEA   DX,spin3_txt
  4840.                CALL  print
  4841.  
  4842. calc_rot:      MOV   AX,cnt_l
  4843.                MOV   DX,cnt_h
  4844.                MOV   CX,37             ; timeout en 2 segundos
  4845. espera_irq6:   CMP   irq6,ON
  4846.                JE    llego_irq6
  4847.                MOV   BX,AX
  4848.                MOV   AL,10000100b
  4849.                OUT   43h,AL            ; 8254: enclavar contador 2
  4850.                DELAY
  4851.                IN    AL,42h
  4852.                XCHG  AH,AL
  4853.                DELAY
  4854.                IN    AL,42h
  4855.                XCHG  AH,AL             ; AX = nueva cuenta
  4856.                CMP   AX,BX
  4857.                JBE   espera_irq6
  4858.                INC   DX
  4859.                LOOP  espera_irq6
  4860.                JMP   err_spin          ; timeout
  4861. llego_irq6:    CMP   iter,2
  4862.                JNE   guarda_tm         ; desechar 2 primeras pruebas
  4863.                XPUSH <AX, DX>
  4864.                MOV   CX,65535
  4865.                SUB   CX,AX
  4866.                MOV   AX,65535
  4867.                MUL   DX                ; DX:AX clocks del 8254
  4868.                ADD   AX,CX
  4869.                ADC   DX,0
  4870.                MOV   dif0_l,AX
  4871.                MOV   dif0_h,DX         ; valor inicial
  4872.                XPOP  <DX, AX>
  4873. guarda_tm:     MOV   cnt_l,AX
  4874.                MOV   cnt_h,DX          ; cuenta actual
  4875.  
  4876.                MOV   AX,65535
  4877.                MUL   DX
  4878.                MOV   CX,65535
  4879.                SUB   CX,cnt_l
  4880.                ADD   AX,CX
  4881.                ADC   DX,0              ; DX:AX clocks 8254 actuales
  4882.  
  4883.                SUB   AX,dif0_l
  4884.                SBB   DX,dif0_h
  4885.                MOV   dif_l,AX
  4886.                MOV   dif_h,DX          ; tiempo transcurrido
  4887.  
  4888.                LEA   BX,fdc_result
  4889.                MOV   CX,7
  4890. sect_rd_res:   CALL  fdc_read          ; leyendo resultados
  4891.                MOV   [BX],AL
  4892.                INC   BX
  4893.                LOOP  sect_rd_res
  4894.                TEST  fdc_result,11000000b  ; ¿error?
  4895.                JNZ   err_spin
  4896.  
  4897.                INC   iter
  4898.                CMP   iter,1000
  4899.                JAE   fin_spin          ; no más de 1000 test
  4900.                JMP   repite_spin
  4901.  
  4902. fin_spin:      XPOP  <DX, DS>          ; **1
  4903.                MOV   AX,250Eh
  4904.                INT   21h               ; restaurar INT 0Eh
  4905.                POP   DS                ; *1
  4906.                CALL  informe_spin
  4907.                RET
  4908. err_spin:      XPOP  <DX, DS>          ; **2
  4909.                MOV   AX,250Eh
  4910.                INT   21h               ; restaurar INT 0Eh
  4911.                POP   DS                ; *2
  4912.                LEA   DX,spine_txt
  4913.                CALL  print             ; indicar que hubo problemas
  4914.                RET
  4915. spin_disk      ENDP
  4916.  
  4917.                ; --- Nueva rutina de INT 0Eh.
  4918.  
  4919. nueva_irq6     PROC
  4920.                PUSH  AX
  4921.                MOV   AL,20h
  4922.                OUT   20h,AL            ; EOI
  4923.                POP   AX
  4924.                MOV   CS:irq6,ON        ; indicar interrupción
  4925. nueva_int23:   IRET
  4926. nueva_irq6     ENDP
  4927.  
  4928.                ; --- Informar sobre la calidad de la disquetera.
  4929.  
  4930. informe_spin   PROC
  4931.                LEA   DX,spind_txt
  4932.                CALL  print
  4933.                PUSH  SI                ; *
  4934.                MOV   DX,cntms_h
  4935.                MOV   AX,cntms_l
  4936.                MOV   DI,3
  4937.                MOV   SI,3392           ; DISI = 200000 (3½ HD)
  4938.                CMP   DX,3
  4939.                JAE   splim_ok
  4940.                CMP   AX,52261
  4941.                JA    splim_ok
  4942.                MOV   DI,2
  4943.                MOV   SI,35594          ; DISI = 166666 (5¼ HD)
  4944. splim_ok:      SUB   AX,SI
  4945.                SBB   DX,DI
  4946.                JNC   spsign_ok
  4947.                ADD   AX,SI
  4948.                ADC   DX,DI
  4949.                XPUSH <AX, DX>          ; signo '-'
  4950.                MOV   DL,'-'
  4951.                MOV   AH,2
  4952.                INT   21h
  4953.                XPOP  <DX, AX>
  4954.                XPUSH <SI, DI>
  4955.                SUB   SI,AX
  4956.                SBB   DI,DX
  4957.                MOV   AX,SI
  4958.                MOV   DX,DI             ; restado el pequeño del grande
  4959.                XPOP  <DI, SI>
  4960.                STC
  4961. spsign_ok:     PUSHF                   ; ** preservar signo
  4962.                CMP   DX,0
  4963.                JNE   fallo_sp          ; muy raro, demasiada diferencia
  4964.                CMP   AX,5000
  4965.                JA    fallo_sp          ; muy raro, demasiada diferencia
  4966.                MOV   CL,01100101b
  4967.                CALL  print_32
  4968.                PUSH  AX                ; ***
  4969.                LEA   DX,spinf1_txt
  4970.                CALL  print
  4971.                MOV   AX,SI
  4972.                MOV   DX,DI
  4973.                MOV   CL,01100111b
  4974.                CALL  print_32
  4975.                LEA   DX,spinf2_txt
  4976.                CALL  print
  4977.                POP   AX                ; ***
  4978.                POPF                    ; **1 signo
  4979.                POP   SI                ; *1
  4980.                LEA   BX,spinf_calidad
  4981.                JC    busca_calidad     ; unidad rápida
  4982.                XOR   AX,AX             ; las lentas siempre buenas ;-)
  4983. busca_calidad: CMP   AX,[BX]
  4984.                JB    dicha_calidad
  4985.                CMP   WORD PTR [BX],0
  4986.                JE    dicha_calidad
  4987.                ADD   BX,4
  4988.                JMP   busca_calidad
  4989. dicha_calidad: MOV   DX,[BX+2]
  4990.                CALL  print             ; imprimir mensaje de calidad
  4991.                LEA   DX,spinf3_txt
  4992.                CALL  print
  4993.                RET
  4994. fallo_sp:      POPF                    ; **2
  4995.                POP   SI                ; *2
  4996.                LEA   DX,spine_txt
  4997.                CALL  print             ; fallo del test
  4998.                RET
  4999. informe_spin   ENDP
  5000.  
  5001. ; ------------ Rutina para dividir números de 48 por números de 15
  5002. ;              bits sin desbordamientos y con cociente de 48 bits.
  5003. ;              DXDISI/AX --> cociente en DXDISI y resto en AX.
  5004. ;              No se modifican otros registros. No se comprueba si
  5005. ;              el divisor es cero o excede los 15 bits.
  5006.  
  5007. divi48x15      PROC
  5008.                PUSH  BX
  5009.                PUSH  CX
  5010.                XOR   BX,BX
  5011.                MOV   CX,49             ; rotar 49 veces
  5012. divi48_15_cmp: CMP   AX,BX
  5013.                JA    divi48_nosub
  5014.                SUB   BX,AX
  5015.                STC
  5016. divi48_nosub:  RCL   SI,1
  5017.                RCL   DI,1
  5018.                RCL   DX,1
  5019.                PUSHF
  5020.                CMP   CX,1
  5021.                JE    divi48_resto      ; ¡no rotar el resto al final!
  5022.                POPF
  5023.                RCL   BX,1
  5024.                PUSHF
  5025. divi48_resto:  POPF
  5026.                LOOP  divi48_15_cmp
  5027.                MOV   AX,BX
  5028.                POP   CX
  5029.                POP   BX
  5030.                RET
  5031. divi48x15      ENDP
  5032.  
  5033. ; ------------ Obtener la unidad física correspondiente a la unidad
  5034. ;              2MGUI o a la indicada. Si la que se indica no es
  5035. ;              además 2MGUI, CF=1 a la vuelta.
  5036.  
  5037. get_drv        PROC
  5038.                MOV   AL,disquetera
  5039.                CMP   AL,-1
  5040.                JNE   usar_esa
  5041.                MOV   AL,0
  5042.                CMP   instalado,ON
  5043.                JNE   usar_esa               ; la A: si no instalado
  5044.                PUSH  ES
  5045.                MOV   ES,tsr_seg
  5046.                MOV   AL,ES:unidad_base      ; por defecto la primera
  5047.                POP   ES
  5048.                MOV   disquetera,AL
  5049. usar_esa:      CALL  drv2mgui?
  5050.                RET
  5051. get_drv        ENDP
  5052.  
  5053. ; ------------ Comprobar si la unidad AL es 2MGUI y devolver en
  5054. ;              ese caso su número físico. AH corrompido.
  5055.  
  5056. drv2mgui?      PROC
  5057.                MOV   AH,0
  5058.                CMP   instalado,ON
  5059.                JNE   drvn2mg           ; si no instalado, no 2MGUI
  5060.                PUSH  ES
  5061.                MOV   ES,tsr_seg
  5062.                MOV   AH,ES:unidad_base
  5063.                POP   ES
  5064.                SUB   AL,AH
  5065.                JZ    drv2mg            ; primera unidad 2MGUI
  5066.                CMP   num_discos,1
  5067.                JE    drvn2mg
  5068.                CMP   AL,1
  5069.                JE    drv2mg            ; segunda unidad 2MGUI
  5070. drvn2mg:       ADD   AL,AH
  5071.                STC
  5072.                RET
  5073. drv2mg:        MOV   AH,info_E.unidad  ; primera unidad
  5074.                AND   AL,AL
  5075.                JZ    drv2mg_ok
  5076.                MOV   AH,info_F.unidad  ; segunda unidad
  5077. drv2mg_ok:     MOV   AL,AH
  5078.                CLC
  5079.                RET
  5080. drv2mgui?      ENDP
  5081.  
  5082. ; ------------ Comprobar si la unidad AL es 2MGUI, A: ó B:
  5083.  
  5084. drvfloppy?     PROC
  5085.                CMP   AL,1
  5086.                JA    es2mgui?          ; no es A: ni B:
  5087.                MOV   DL,AL
  5088.                MOV   AH,8
  5089.                MOV   BL,0
  5090.                CALL  tipo_disco        ; tipo de la unidad
  5091.                CMP   BL,2
  5092.                JE    drvflp            ; de alta densidad
  5093.                CMP   BL,4
  5094.                JAE   drvflp            ; de alta densidad
  5095. es2mgui?:      CALL  drv2mgui?
  5096.                RET
  5097. drvflp:        CLC
  5098.                RET
  5099. drvfloppy?     ENDP
  5100.  
  5101. ; ------------ Inicializar datos para las rutinas de bajo nivel.
  5102. ;              A la entrada, AL = unidad física.
  5103.  
  5104. init_flp       PROC
  5105.                PUSH  AX
  5106.                LEA   SI,info_E         ; apuntar a datos de la unidad
  5107.                MOV   BX,GAPDEF
  5108.                MOV   CL,modoDMA
  5109.                CMP   instalado,ON
  5110.                JNE   flpn_ok           ; usar la primera si no reside
  5111.                PUSH  ES
  5112.                MOV   ES,tsr_seg
  5113.                MOV   BX,ES:gaprw
  5114.                MOV   CL,ES:modoDMA
  5115.                CMP   AL,ES:info_E.unidad  ; utilizar la correcta si el
  5116.                POP   ES                   ; programa está residente
  5117.                JE    flpn_ok
  5118.                LEA   SI,info_F
  5119. flpn_ok:       MOV   [SI].unidad,AL    ; en adelante, la unidad física
  5120.                MOV   gaprw,BX
  5121.                MOV   modoDMA,CL        ; GAP/modo DMA correcto
  5122.                CALL  get_tpista
  5123.                MOV   [SI].infb.tpista1,AX   ; bytes por pista 1ª parte
  5124.                MOV   [SI].infb.tpista2,BX   ; bytes por pista 2ª parte
  5125.                MOV   tpistamax1,CX     ; bytes máximos teóricos 1ª parte
  5126.                MOV   tpistamax2,DX     ; bytes máximos teóricos 2ª parte
  5127.                MOV   BL,7              ; log2 (16384) - 7 = 7
  5128.                CMP   AX,16384
  5129.                JBE   tsecf_ok
  5130.                INC   BL                ; log2 (32768) - 7 = 8
  5131. tsecf_ok:      MOV   [SI].tsector,BL
  5132.                MOV   AX,DI
  5133.                MOV   [SI].vunidad1,AL
  5134.                MOV   [SI].infb.vunidad2,AH
  5135.                MOV   AX,bsectini
  5136.                MOV   [SI].bytes_sector,AX
  5137.                POP   AX
  5138.                RET
  5139. init_flp       ENDP
  5140.  
  5141. ; ------------ Devolver tamaño de la pista (para la unidad AL)
  5142. ;              en AX (pistas 1ª parte) y BX (2ª parte) así como los
  5143. ;              límites máximos en CX (1ª parte) y DX (2ª parte) y
  5144. ;              las velocidades de transferencia en DI.
  5145.  
  5146. get_tpista     PROC
  5147.                MOV   DL,AL
  5148.                MOV   AH,8
  5149.                CALL  tipo_disco        ; tipo de la unidad
  5150.                LEA   AX,pista_525
  5151.                CMP   BL,2
  5152.                JE    infpis_ok         ; 1.2M
  5153.                LEA   AX,pista_35
  5154.                CMP   BL,4              ; 1.44M
  5155.                JE    infpis_ok
  5156.                CMP   param_ed,ON
  5157.                JNE   infpis_ok
  5158.                LEA   AX,pista_ed       ; 2.88M
  5159. infpis_ok:     MOV   BX,10             ; offset información DD
  5160.                CMP   param_dd,ON
  5161.                JE    infdis_ok
  5162.                MOV   BX,20             ; offset información DH
  5163.                CMP   param_dh,ON
  5164.                JE    infdis_ok
  5165.                XOR   BX,BX             ; offset información HD
  5166. infdis_ok:     ADD   BX,AX             ; direccionar tabla datos
  5167.                MOV   AX,tpista
  5168.                CMP   param_b,ON
  5169.                JE    tp1_ok            ; indicado con /B
  5170.                MOV   AX,[BX]
  5171. tp1_ok:        MOV   CX,[BX+2]
  5172.                MOV   DX,[BX+6]
  5173.                MOV   DI,[BX+8]
  5174.                MOV   BX,[BX+4]
  5175.                CMP   param_b,ON
  5176.                JNE   tp2_ok
  5177.                CMP   param_dh,ON
  5178.                JNE   tp3_ok
  5179.  
  5180.                XPUSH <SI, DI, CX, DX>  ; * caso 5¼ /DH
  5181.                MUL   WORD PTR maxpistas
  5182.                MOV   DI,DX
  5183.                MOV   SI,AX
  5184.                MOV   AX,t_525_hd       ; tamaño * maxpistas * t_525_hd
  5185.                CALL  mult32x16
  5186.                MOV   AX,20
  5187.                CALL  divi48x15         ; div 20 (problema de rango)
  5188.                XPUSH <DX, DI, SI>
  5189.                MOV   AX,WORD PTR maxpistas
  5190.                SUB   AL,frontera
  5191.                SBB   AH,0
  5192.                MOV   BX,t_525_dd
  5193.                MUL   BX
  5194.                MOV   CX,DX
  5195.                MOV   BX,AX             ; CX:BX = t_525_dd*(maxp - FRO)
  5196.                XOR   DI,DI
  5197.                MOV   SI,t_525_hd
  5198.                MOV   AL,frontera
  5199.                MOV   AH,0
  5200.                CALL  mult32x16
  5201.                ADD   SI,BX
  5202.                ADC   DI,CX
  5203.                ADC   DX,0              ; denominador
  5204.                MOV   AX,20
  5205.                SUB   SI,24             ; redondeo
  5206.                SBB   DI,0
  5207.                SBB   DX,0
  5208.                CALL  divi48x15         ; div 20 (problema de rango)
  5209.                MOV   AX,SI             ; cabe en 15 bits
  5210.                XPOP  <SI, DI, DX>
  5211.                CALL  divi48x15
  5212.                INC   SI                ; redondeo por el resto
  5213.                MOV   AX,SI             ; tamaño primera parte disco
  5214.                PUSH  AX                ; **
  5215.                MOV   BX,t_525_dd
  5216.                MUL   BX
  5217.                MOV   BX,t_525_hd
  5218.                DIV   BX
  5219.                MOV   BX,AX             ; tamaño segunda parte disco
  5220.                POP   AX                ; **
  5221.                XPOP  <DX, CX, DI, SI>  ; *
  5222.                JMP   tp2_ok
  5223.  
  5224. tp3_ok:        MOV   BX,AX             ; /B afecta a todo el disco
  5225. tp2_ok:        RET
  5226. get_tpista     ENDP
  5227.  
  5228. ; ------------ Imprimir nº de 8 bits en AL.
  5229.  
  5230. print_8        PROC
  5231.                XPUSH <AX, CX, DX>
  5232.                MOV   AH,0
  5233.                XOR   DX,DX
  5234.                MOV   CL,2
  5235.                CALL  print_32
  5236.                XPOP  <DX, CX AX>
  5237.                RET
  5238. print_8        ENDP
  5239.  
  5240. ; --- Imprimir un nº decimal de 32 bits en DXAX formateado por CL.
  5241. ;
  5242. ; Entradas:
  5243. ;       Si bit 4  = 1 --> se imprimirán signos separadores de millar
  5244. ;       bits  0-3 = nº total de dígitos (incluyendo separadores de
  5245. ;                   millar y parte fraccional)
  5246. ;       bits  5-7 = nº de dígitos de la parte fraccional (cuantos
  5247. ;                   dígitos de DXAX, empezando por la derecha,
  5248. ;                   se consideran parte fraccional, e irán precedidos
  5249. ;                   del correspondiente separador)
  5250. ;
  5251. ; Salidas: nº impreso, ningún registro modificado.
  5252. ;
  5253. ; * Ejemplo, si DXAX=9384320 y  CL=010 1 1011
  5254. ;   se imprimirá ( '_' representa un espacio en blanco ):  __93.843,20
  5255.  
  5256. print_32       PROC
  5257.                PUSH  DS
  5258.                PUSH  ES
  5259.                PUSH  CS
  5260.                PUSH  CS
  5261.                POP   DS
  5262.                POP   ES
  5263.                PUSH  AX                ; preservar todos los registros
  5264.                PUSH  BX
  5265.                PUSH  CX
  5266.                PUSH  DX
  5267.                PUSH  SI
  5268.                PUSH  DI
  5269.                PUSHF
  5270.                MOV   formato_pr32,CL   ; byte del formato de impresión elegido
  5271.                MOV   CX,",."
  5272.                CMP   idioma_sp,ON
  5273.                JE    separ_pr32
  5274.                XCHG  CH,CL
  5275. separ_pr32:    MOV   millares_pr32,CL  ; separador de millares
  5276.                MOV   fracc_pr32,CH     ; separador parte fraccional
  5277.                MOV   BX,OFFSET tabla_pr32
  5278.                MOV   CX,10
  5279. digit_pr32:    PUSH  CX
  5280.                PUSH  AX
  5281.                PUSH  DX
  5282.                XOR   DI,DI
  5283.                MOV   SI,1              ; DISI = 1
  5284.                DEC   CX                ; CX - 1
  5285.                JCXZ  hecho_pr32
  5286. factor_pr32:   SAL   SI,1
  5287.                RCL   DI,1              ; DISI * 2
  5288.                MOV   DX,DI
  5289.                MOV   AX,SI
  5290.                SAL   SI,1
  5291.                RCL   DI,1
  5292.                SAL   SI,1
  5293.                RCL   DI,1              ; DISI * 8
  5294.                ADD   SI,AX
  5295.                ADC   DI,DX             ; DISI = DISI*8 + DISI*2 = DISI*10
  5296.                LOOP  factor_pr32       ; DISI = DISI*10*10* ... (CX-1 veces)
  5297. hecho_pr32:    POP   DX                ; luego DISI = 10 elevado a (CX-1)
  5298.                POP   AX                ; CX se recuperará más tarde
  5299.                MOV   CL,0FFh
  5300. rep_sub_pr32:  INC   CL
  5301.                SUB   AX,SI
  5302.                SBB   DX,DI             ; DXAX = DXAX - DISI
  5303.                JNC   rep_sub_pr32      ; restar el factor cuanto se pueda
  5304.                ADD   AX,SI             ; subsanar el desbordamiento:
  5305.                ADC   DX,DI             ; DXAX = DXAX + DISI
  5306.                ADD   CL,'0'            ; pasar binario a ASCII
  5307.                MOV   [BX],CL
  5308.                POP   CX                ; CX se recupera ahora
  5309.                INC   BX
  5310.                LOOP  digit_pr32        ; próximo dígito del número
  5311.                STD                     ; transferencias (MOVS) hacia atrás
  5312.                DEC   BX                ; BX apunta al último dígito
  5313.                MOV   final_pr32,BX     ; último dígito
  5314.                MOV   ent_frac_pr32,BX  ; frontera parte entera/fraccional
  5315.                MOV   CL,5
  5316.                MOV   AL,formato_pr32
  5317.                SHR   AL,CL             ; AL = nº de decimales
  5318.                AND   AL,AL
  5319.                JZ    no_frac_pr32      ; ninguno
  5320.                MOV   CL,AL
  5321.                XOR   CH,CH
  5322.                MOV   SI,final_pr32
  5323.                MOV   DI,SI
  5324.                INC   DI
  5325.                REP   MOVSB             ; correr cadena arriba (hacer hueco)
  5326.                INC   final_pr32
  5327.                MOV   AL,fracc_pr32
  5328.                MOV   [DI],AL           ; poner separador de parte fraccional
  5329.                MOV   ent_frac_pr32,SI  ; indicar nueva frontera
  5330. no_frac_pr32:  MOV   AL,formato_pr32
  5331.                TEST  AL,16             ; interpretar el formato especificado
  5332.                JZ    poner_pr32        ; imprimir como tal
  5333. entera_pr32:   MOV   CX,final_pr32     ; añadir separadores de millar
  5334.                SUB   CX,ent_frac_pr32
  5335.                ADD   CX,3
  5336.                MOV   SI,final_pr32
  5337.                MOV   DI,SI
  5338.                INC   DI
  5339.                REP   MOVSB             ; correr cadena arriba (hacer hueco)
  5340.                MOV   AL,millares_pr32
  5341.                MOV   [DI],AL           ; poner separador de millares
  5342.                INC   final_pr32
  5343.                MOV   ent_frac_pr32,SI  ; usar esta variable como puntero
  5344.                SUB   SI,OFFSET tabla_pr32
  5345.                CMP   SI,3
  5346.                JAE   entera_pr32       ; próximo separador
  5347. poner_pr32:    MOV   BX,final_pr32
  5348.                MOV   BYTE PTR [BX+1],0 ; delimitador de fin de cadena
  5349.                MOV   BX,OFFSET tabla_pr32
  5350.                MOV   principio_pr32,BX ; inicio de cadena
  5351. limpiar_pr32:  MOV   AL,[BX]
  5352.                CMP   AL,'0'
  5353.                JE    blanco_pr32       ; cero a la izda --> poner " "
  5354.                CMP   AL,millares_pr32  ; separador millares a la izda
  5355.                JE    blanco_pr32
  5356.                CMP   AL,fracc_pr32
  5357.                JNE   acabar_pr32
  5358.                MOV   BYTE PTR [BX-1],'0' ; reponer 0 antes de la coma
  5359.                DEC   principio_pr32
  5360. acabar_pr32:   MOV   AL,formato_pr32   ; imprimir
  5361.                AND   AL,00001111b
  5362.                XOR   AH,AH
  5363.                MOV   DX,final_pr32
  5364.                SUB   DX,AX
  5365.                INC   DX                ; DX = offset 'principio'
  5366.                AND   AX,AX
  5367.                JNZ   format_pr32       ; longitud especificada por el usuario
  5368.                MOV   DX,principio_pr32 ; longitud obtenida del número
  5369. format_pr32:   CALL  print
  5370.                POPF                    ; restaurar todos los registros
  5371.                POP   DI
  5372.                POP   SI
  5373.                POP   DX
  5374.                POP   CX
  5375.                POP   BX
  5376.                POP   AX
  5377.                POP   ES
  5378.                POP   DS
  5379.                RET                     ; salida del procedimiento
  5380. blanco_pr32:   MOV   BYTE PTR [BX],' ' ; sustituir 0 ó separador de millares
  5381.                INC   BX                ; a la izda. por espacio en blanco
  5382.                INC   principio_pr32
  5383.                CMP   BX,final_pr32
  5384.                JB    limpiar_pr32
  5385.                MOV   DX,BX             ; es el número 0.000.000.00X
  5386.                JMP   SHORT acabar_pr32 ; imprimir
  5387. formato_pr32   DB    0
  5388.                DB    5 DUP (' ')       ; espacios en blanco para cubrir la
  5389.                                        ; mayor plantilla que pueda ser espe-
  5390.                                        ; cificada en el formato
  5391. tabla_pr32     DT    0                 ; reservar 14 bytes (nº más ., más ASCIIZ)
  5392.                DW    0,0               ; aquí se solapa un buffer de 32 bytes
  5393. millares_pr32  DB    '.'               ; separador de millares
  5394. fracc_pr32     DB    ','               ;     "     parte fraccional
  5395. final_pr32     DW    0                 ; offset al último byte a imprimir
  5396. principio_pr32 DW    0                 ;  "     "  primer   "  "     "
  5397. ent_frac_pr32  DW    0                 ; offset a la frontera entero-fracc.
  5398.                DT    0                 ; $ - tabla_pr32 = 32 bytes usados por
  5399.                                        ; INT 21h al principio de print_32
  5400. print_32       ENDP
  5401.  
  5402. ; ------------ Crear tabla con información para formatear.
  5403.  
  5404. genera_infof   PROC
  5405.                XPUSHA
  5406.                PUSH  ES
  5407.                MOV   ES,sbuffer
  5408.                MOV   AL,[SI].infb.mfrontera
  5409.                CMP   [SI].cilindro,AL  ; 1ª/2ª mitad del disco
  5410.                MOV   AX,tpistamax1
  5411.                JB    pl_ok
  5412.                MOV   AX,tpistamax2
  5413. pl_ok:         SUB   AX,146            ; respetar inicio pista
  5414.                XOR   DX,DX
  5415.                MOV   CX,256+62+PRE_GAP3
  5416.                DIV   CX                ; AX sectores de 256 bytes caben
  5417.                MOV   CX,AX
  5418.                MOV   BX,360            ; grados de la circunferencia
  5419.                MOV   AX,sliding_x
  5420.                MUL   CX
  5421.                DIV   BX                ; AL = sliding X en sectores
  5422.                PUSH  AX                ; *
  5423.                MOV   AX,sliding_y
  5424.                MUL   CX
  5425.                DIV   BX                ; AL = sliding Y en sectores
  5426.                POP   BX                ; *
  5427.                MOV   AH,AL             ; sliding Y
  5428.                MOV   AL,BL             ; sliding X
  5429.                PUSH  AX                ; *
  5430.                ADD   AL,AH
  5431.                MOV   AH,[SI].cilindro
  5432.                INC   AH                ; desplazar incluso cilindro 0
  5433.                MUL   AH                ; (cilindro+1) * (X+Y)
  5434.                MOV   DX,AX
  5435.                POP   AX                ; *
  5436.                MUL   [SI].cabezal      ; cabezal * X
  5437.                ADD   AX,DX
  5438.                XOR   DX,DX             ; DX:AX = cil * (X+Y) + cab * X
  5439.                DIV   CX                ; DL = DX:AX MOD sectores = dis
  5440.                SUB   DL,CL
  5441.                NEG   DL                ; DL = sectores - dis
  5442.                INC   DL                ; primer_sector
  5443.                CMP   DL,CL
  5444.                JB    gen_ps_ok
  5445.                MOV   DL,0
  5446. gen_ps_ok:     MOV   BL,CL             ; nº sectores
  5447.                MOV   AL,[SI].cabezal
  5448.                MOV   AH,1
  5449.                XOR   DI,DI
  5450.                MOV   ES:[DI],CL        ; sectores
  5451.                MOV   ES:[DI+1],AH      ; de tamaño 1 (256 bytes)
  5452.                MOV   DH,[SI].cilindro
  5453.                ADD   DI,2
  5454. gen_info:      MOV   ES:[DI],DH        ; cilindro
  5455.                MOV   ES:[DI+1],AL      ; cabezal
  5456.                MOV   ES:[DI+2],DL      ; sector
  5457.                MOV   ES:[DI+3],AH      ; tamaño 1 (256 bytes)
  5458.                AND   DL,DL
  5459.                JNZ   gen_tam_ok
  5460.                MOV   AH,[SI].tsector
  5461.                MOV   ES:[DI+3],AH      ; el sector 0 es especial
  5462.                MOV   AH,1
  5463. gen_tam_ok:    INC   DL
  5464.                CMP   DL,BL
  5465.                JB    gen_sec_ok
  5466.                MOV   DL,0              ; comenzar desde sector 0
  5467. gen_sec_ok:    ADD   DI,4
  5468.                LOOP  gen_info
  5469.                POP   ES
  5470.                XPOPA
  5471.                RET
  5472. genera_infof   ENDP
  5473.  
  5474. ; ------------ Formatear una pista.
  5475.  
  5476. formatea_pista PROC
  5477.                XPUSHA                  ; *
  5478.                PUSH  ES                ; **
  5479.                MOV   ES,sbuffer
  5480.                MOV   CL,ES:[0]
  5481.                MOV   CH,0              ; CX sectores
  5482.                SHL   CX,1
  5483.                SHL   CX,1
  5484.                DEC   CX                ; nº de bytes - 1
  5485.                MOV   AX,ES
  5486.                MOV   DI,2
  5487.                CALL  calc_dir_DMA      ; AX:DI -> base BX y página AH
  5488.                MOV   AL,F_WRITE        ; modo DMA para escribir
  5489.                CALL  _prepara_DMA      ; programar realmente el DMA
  5490.                MOV   AL,F_FORMAT
  5491.                CALL  fdc_write
  5492.                JC    fallo_fmt
  5493.                MOV   AL,[SI].cabezal
  5494.                SHL   AL,1
  5495.                SHL   AL,1
  5496.                OR    AL,[SI].unidad
  5497.                CALL  fdc_write         ; byte 1 de la orden
  5498.                JC    fallo_fmt
  5499.                MOV   AL,ES:[1]
  5500.                CALL  fdc_write         ; tamaño general
  5501.                JC    fallo_fmt
  5502.                MOV   AL,ES:[0]
  5503.                CALL  fdc_write         ; nº sectores
  5504.                MOV   AL,PRE_GAP3
  5505.                CALL  fdc_write         ; GAP3
  5506.                MOV   AL,4Eh
  5507.                CALL  reset_irq
  5508.                CALL  fdc_write         ; byte de relleno 4Eh (GAP)
  5509.                CALL  espera_int
  5510. fallo_fmt:     PUSHF
  5511.                LEA   BX,fdc_result
  5512.                MOV   CX,7
  5513. format_res:    CALL  fdc_read          ; leyendo resultados
  5514.                MOV   [BX],AL
  5515.                INC   BX
  5516.                LOOP  format_res
  5517.                POPF
  5518.                JC    fallo_format
  5519.                TEST  fdc_result,11000000b
  5520.                JZ    format_ret
  5521. fallo_format:  STC                     ; fallo
  5522.                CALL  set_err
  5523. format_ret:    POP   ES                ; **
  5524.                XPOPA                   ; *
  5525.                RET
  5526. formatea_pista ENDP
  5527.  
  5528. ; ------------ Devolver nº aleatorio de 16 bits en AX.
  5529.  
  5530. rnd            PROC
  5531.                CMP   semilla,0
  5532.                JNE   dev_rnd
  5533.                PUSH  DS
  5534.                MOV   AX,40h
  5535.                MOV   DS,AX
  5536.                MOV   AX,DS:[6Ch]       ; contador hora BIOS
  5537.                POP   DS                ; como semilla
  5538.                MOV   semilla,AX
  5539. dev_rnd:       XPUSH <BX, CX>
  5540.                MOV   AX,semilla
  5541.                MOV   BX,AX
  5542.                MOV   CL,7
  5543.                SHR   AX,CL
  5544.                XOR   AX,BX
  5545.                AND   AX,1
  5546.                ROR   AX,1
  5547.                SHR   BX,1
  5548.                OR    AX,BX
  5549.                MOV   semilla,AX
  5550.                XPOP  <CX, BX>
  5551.                RET
  5552. semilla        DW    0
  5553. rnd            ENDP
  5554.  
  5555.  
  5556. ; ***********************************************
  5557. ; *                                             *
  5558. ; *   D A T O S    N O    R E S I D E N T E S   *
  5559. ; *                                             *
  5560. ; ***********************************************
  5561.  
  5562. ; ------------ Parámetros soportados
  5563.  
  5564. param_ayuda    DB    OFF       ; a ON si se indicó /? /H ó ?
  5565. param_dd       DB    OFF       ; a ON si se indicó /DD
  5566. param_dh       DB    OFF       ; a ON si se indicó /DH
  5567. param_ed       DB    OFF       ; a ON si se indicó /ED
  5568. param_dron     DB    OFF       ; a ON si se indicó /DRON
  5569. param_droff    DB    OFF       ; a ON si se indicó /DROFF
  5570. param_dwon     DB    OFF       ; a ON si se indicó /DWON
  5571. param_dwoff    DB    OFF       ; a ON si se indicó /DWOFF
  5572. param_n        DB    OFF       ; a ON si se indicó /N
  5573. param_k        DB    OFF       ; a ON si se indicó /K
  5574. param_test     DB    OFF       ; a ON si se indicó /TEST
  5575. param_nodma    DB    OFF       ; a ON si se indicó /NODMA
  5576. param_ems      DB    OFF       ; a ON si se indicó /EMS
  5577. param_q        DB    OFF       ; a ON si se indicó /Q
  5578. param_t        DB    OFF       ; a ON si se indicó /T=
  5579. param_r        DB    OFF       ; a ON si se indicó /R=
  5580. param_c        DB    OFF       ; a ON si se indicó /C=
  5581. param_s        DB    OFF       ; a ON si se indicó /S=
  5582. param_f        DB    OFF       ; a ON si se indicó /F=
  5583. param_b        DB    OFF       ; a ON si se indicó /B=
  5584. param_x        DB    OFF       ; a ON si se indicó /X=
  5585. param_y        DB    OFF       ; a ON si se indicó /Y=
  5586. param_m        DB    OFF       ; a ON si se indicó /M=
  5587. param_g        DB    OFF       ; a ON si se indicó /G=
  5588. ptr_label      DW    0         ; != NULL si se indicó /L
  5589. ptr_ilabel     DW    0         ; != NULL si se indicó /V
  5590. disquetera     DB    -1        ; unidad seleccionada si se indica
  5591.  
  5592. parametros     LABEL BYTE
  5593.                DB    "*:",3
  5594.                DB    'A'
  5595.                DB    26
  5596.                DW    disquetera
  5597.  
  5598.                DB    "?",0
  5599.                DW    param_ayuda
  5600.                DB    ON
  5601.  
  5602.                DB    "/?",0
  5603.                DW    param_ayuda
  5604.                DB    ON
  5605.  
  5606.                DB    "/H",0
  5607.                DW    param_ayuda
  5608.                DB    ON
  5609.  
  5610.                DB    "/DD",0
  5611.                DW    param_dd
  5612.                DB    ON
  5613.  
  5614.                DB    "/DH",0
  5615.                DW    param_dh
  5616.                DB    ON
  5617.  
  5618.                DB    "/ED",0
  5619.                DW    param_ed
  5620.                DB    ON
  5621.  
  5622.                DB    "/DRON",0
  5623.                DW    param_dron
  5624.                DB    ON
  5625.  
  5626.                DB    "/DROFf",0
  5627.                DW    param_droff
  5628.                DB    ON
  5629.  
  5630.                DB    "/DWON",0
  5631.                DW    param_dwon
  5632.                DB    ON
  5633.  
  5634.                DB    "/DWOFf",0
  5635.                DW    param_dwoff
  5636.                DB    ON
  5637.  
  5638.                DB    "/TEst",0
  5639.                DW    param_test
  5640.                DB    ON
  5641.  
  5642.                DB    "/NOdma",0
  5643.                DW    param_nodma
  5644.                DB    ON
  5645.  
  5646.                DB    "/EMs",0
  5647.                DW    param_ems
  5648.                DB    ON
  5649.  
  5650.                DB    "/B",1
  5651.                DW    0, MPISTA
  5652.                DW    tpista
  5653.                DW    param_b
  5654.                DB    ON
  5655.  
  5656.                DB    "/X",1
  5657.                DW    0, 359
  5658.                DW    sliding_x
  5659.                DW    param_x
  5660.                DB    ON
  5661.  
  5662.                DB    "/Y",1
  5663.                DW    0, 359
  5664.                DW    sliding_y
  5665.                DW    param_y
  5666.                DB    ON
  5667.  
  5668.                DB    "/M",1
  5669.                DW    0, 86
  5670.                DW    frontera
  5671.                DW    param_m
  5672.                DB    ON
  5673.  
  5674.                DB    "/G",1
  5675.                DW    0, 999
  5676.                DW    gaprw
  5677.                DW    param_g
  5678.                DB    ON
  5679.  
  5680.                DB    "/N",0
  5681.                DW    param_n
  5682.                DB    ON
  5683.  
  5684.                DB    "/K",0
  5685.                DW    param_k
  5686.                DB    ON
  5687.  
  5688.                DB    "/I",0
  5689.                DW    param_i
  5690.                DB    ON
  5691.  
  5692.                DB    "/Q",0
  5693.                DW    param_q
  5694.                DB    ON
  5695.  
  5696.                DB    "/T",1
  5697.                DW    80, 86
  5698.                DW    maxpistas
  5699.                DW    param_t
  5700.                DB    ON
  5701.  
  5702.                DB    "/C",2
  5703.                DW    8,128,256,512,1024,2048,4096,8192,16384
  5704.                DW    tcluster
  5705.                DW    param_c
  5706.                DB    ON
  5707.  
  5708.                DB    "/S",2
  5709.                DW    3,128,256,512
  5710.                DW    bsectini
  5711.                DW    param_s
  5712.                DB    ON
  5713.  
  5714.                DB    "/R",1
  5715.                DW    1, 240
  5716.                DW    rootdir
  5717.                DW    param_r
  5718.                DB    ON
  5719.  
  5720.                DB    "/F",1
  5721.                DW    1, 2
  5722.                DW    nfats
  5723.                DW    param_f
  5724.                DB    ON
  5725.  
  5726.                DB    "/L",4
  5727.                DW    ptr_label
  5728.  
  5729.                DB    "/V",4
  5730.                DW    ptr_ilabel
  5731.  
  5732.                DB    0                 ; fin de la tabla
  5733.  
  5734. ; ------------ Constantes y variables
  5735.  
  5736. ON             EQU    1                ; constantes booleanas
  5737. OFF            EQU    0
  5738.  
  5739. ERRSINTAX      EQU    1                ; tipos de errores
  5740. MALDOS         EQU    2
  5741. MALDRV         EQU    4
  5742. MALBIOS        EQU    8
  5743. ERRRANGO       EQU   16
  5744. POCAMEM        EQU   32
  5745. YAINST         EQU   64
  5746. NOINST         EQU  128
  5747. MX64FULL       EQU  256
  5748. DMACRUCE       EQU  512
  5749. DMAPOCO        EQU 1024
  5750. PARAMCONFIG    EQU 2048
  5751.  
  5752. ABORTADO       EQU    8
  5753. NOPREP         EQU   16
  5754. MALADENS       EQU   32
  5755. PROTESCR       EQU   64
  5756. MALSYS         EQU  128
  5757. MUCHAFAT       EQU  256
  5758. MUCHAPISTA     EQU  512
  5759.  
  5760. error          DW    0                 ; de instalación
  5761. errw           DW    0                 ; al formatear/test, etc.
  5762. disco          DB    ?
  5763. emmtipo        DW    ?                 ; tipo de EMM en INT 4Bh
  5764. psp            DW    ?                 ; dirección del PSP
  5765.  
  5766. emm_id         DB    "EMMXXXX0"        ; identificación controlador EMS
  5767.  
  5768. emm_nombre     DB    "2MGUI",0,0,0     ; nombre para el handle EMS
  5769.  
  5770. null           DB    "NUL",0           ; dispositivo NUL
  5771.  
  5772. instalado      DB    ?                 ; a ON si 2MGUI instalado
  5773.  
  5774. offsets_ints   DW    3         ; número de vectores interceptados
  5775.                DB    8h        ; tabla de offsets de los vectores
  5776.                DW    ges_int08 ; de interrupción interceptados
  5777.                DB    13h
  5778.                DW    ges_int13
  5779.                DB    2Fh
  5780.                DW    ges_int2F
  5781.  
  5782.                ; --- El disco está dividido en dos partes: desde el
  5783.                ;     cilindro 0 hasta FRONTERA-1 y desde FRONTERA
  5784.                ;     hasta maxpistas-1. Cada parte tiene sus propias
  5785.                ;     características (en la práctica, sólo en 360DH).
  5786.  
  5787. pista_525      LABEL WORD
  5788.                DW    t_525_hd          ; 1.2M           1ª parte HD
  5789.                DW    m_525_hd          ; límite físico  1ª parte HD
  5790.                DW    t_525_hd          ; 1.2M           2ª parte HD
  5791.                DW    m_525_hd          ; límite físico  2ª parte HD
  5792.                DW    0000h             ; velocidad
  5793.                DW    t_525_dd          ; 1.2M           1ª parte DD
  5794.                DW    m_525_dd          ; límite físico  1ª parte DD
  5795.                DW    t_525_dd          ; 1.2M           2ª parte DD
  5796.                DW    m_525_dd          ; límite físico  2ª parte DD
  5797.                DW    0101h             ; velocidad
  5798.                DW    t_525_hd          ; 1.2M           1ª parte DH
  5799.                DW    m_525_hd          ; límite físico  1ª parte DH
  5800.                DW    t_525_dd          ; 1.2M           2ª parte DH
  5801.                DW    m_525_dd          ; límite físico  2ª parte DH
  5802.                DW    0100h             ; velocidad
  5803. pista_35       LABEL WORD
  5804.                DW    t_35_hd           ; 1.44M          1ª parte HD
  5805.                DW    m_35_hd           ; límite físico  1ª parte HD
  5806.                DW    t_35_hd           ; 1.44M          2ª parte HD
  5807.                DW    m_35_hd           ; límite físico  2ª parte HD
  5808.                DW    0000h             ; velocidad
  5809.                DW    t_35_dd           ; 1.44M          1ª parte DD
  5810.                DW    m_35_dd           ; límite físico  1ª parte DD
  5811.                DW    t_35_dd           ; 1.44M          2ª parte DD
  5812.                DW    m_35_dd           ; límite físico  2ª parte DD
  5813.                DW    0101h             ; velocidad
  5814.                DW    t_35_dd           ; 1.44M          1ª parte DD
  5815.                DW    m_35_dd           ; límite físico  1ª parte DD
  5816.                DW    t_35_dd           ; 1.44M          2ª parte DD
  5817.                DW    m_35_dd           ; límite físico  2ª parte DD
  5818.                DW    0101h             ; velocidad
  5819. pista_ed       LABEL WORD
  5820.                DW    t_35_ed           ; 2.88M          1ª parte ED
  5821.                DW    m_35_ed           ; límite físico  1ª parte ED
  5822.                DW    t_35_ed           ; 2.88M          2ª parte ED
  5823.                DW    m_35_ed           ; límite físico  2ª parte ED
  5824.                DW    0303h             ; velocidad
  5825.                DW    t_35_ed           ; 2.88M          1ª parte ED
  5826.                DW    m_35_ed           ; límite físico  1ª parte ED
  5827.                DW    t_35_ed           ; 2.88M          2ª parte ED
  5828.                DW    m_35_ed           ; límite físico  2ª parte ED
  5829.                DW    0303h             ; velocidad
  5830.                DW    t_35_ed           ; 2.88M          1ª parte ED
  5831.                DW    m_35_ed           ; límite físico  1ª parte ED
  5832.                DW    t_35_ed           ; 2.88M          2ª parte ED
  5833.                DW    m_35_ed           ; límite físico  2ª parte ED
  5834.                DW    0303h             ; velocidad
  5835.  
  5836. maxpistas      DB   PISTAS
  5837.                DB    0      ; ¡la captura de parámetros usa DW, no DB!
  5838. rootdir        DW   MINROOT ; mínimo por defecto
  5839. bsectini       DW   SECTDEF ; tamaño de sector por defecto
  5840. tcluster       DW   CLUSDEF ; tamaño de clúster por defecto
  5841. nfats          DB    1
  5842.                DB    0     ; ¡la captura de parámetros usa DW, no DB!
  5843. tipofat        DB    ?
  5844. fbuffer        DW    0     ; segmento para la FAT
  5845. srootdir       DW    ?     ; sectores ocupados por el raíz
  5846.  
  5847. tpista         DW    ?         ; valor de /B= si se indica
  5848. tpistamax1     DW    ?         ; bytes por pista físicamente máximos
  5849. tpistamax2     DW    ?         ; ...y en la segunda parte del disco
  5850. sliding_x      DW    SLID_X    ; grados angulares de sliding /X
  5851. sliding_y      DW    SLID_Y    ; grados angulares de sliding /Y
  5852. frontera       DB    FRONT     ; frontera división del disco 2 mitades
  5853.                DB    0         ; ¡la captura de parámetros usa DW, no DB!
  5854.  
  5855. tmodo          DB    ?         ; 0->pista a 0, 1->con datos aleatorios
  5856. bytes_ok       DW    ?         ; bytes bien leídos durante el test
  5857. bytes_max      DW    ?         ; máximos bytes soportados último éxito
  5858. tmax           DW    ?         ; máximo/mínima capacidad por pista
  5859. tmin           DW    ?         ; durante el test
  5860. iter           DW    ?         ; contador de iteraciones
  5861. irq6           DB    ?         ; a ON cuando llega dicha IRQ en el test
  5862. cnt_h          DW    ?         ; contadores de tiempo para spin
  5863. cnt_l          DW    ?
  5864. dif_l          DW    0         ; variación de los contadores
  5865. dif_h          DW    0
  5866. cntms_h        DW    0         ; milisegundos * 1000
  5867. cntms_l        DW    0
  5868. dif0_l         DW    0         ; valor inicial
  5869. dif0_h         DW    0
  5870.  
  5871. sector_boot    LABEL BYTE           ; sector de arranque de 128 bytes
  5872.                JMP   SHORT arranque
  5873.                NOP
  5874.                DB    "2MGUI-10"     ; ID sistema: versión 1.0
  5875. boot_tsect     DW    ?              ; bytes/sector
  5876. bscluster      DB    ?              ; sectores por cluster
  5877.                DW    1              ; sectores reservados al principio
  5878. bnfats         DB    ?              ; nº copias de la FAT
  5879. brootdir       DW    ?              ; entradas al directorio raíz
  5880. bsectores      DW    ?              ; nº total de sectores del disco
  5881. media_id       DB    0FAh           ; byte descriptor de medio
  5882. bsectfat       DW    ?              ; sectores ocupados por la FAT
  5883.                DW    1              ; sectores por pista
  5884.                DW    1              ; nº de cabezales
  5885.                DD    0              ; sectores especiales reservados
  5886.                DD    0              ; nº sectores (unidad 32 bit)
  5887.                DB    0              ; unidad física
  5888.                DB    0              ; reservado
  5889.                DB    29h            ; disco con número de serie
  5890. bserie         DD    12345678h      ; número de serie
  5891.                DB    "NO NAME    "  ; título del disco
  5892. ftipo          DB    "FAT12   "     ; tipo de FAT
  5893. arranque:      CLI
  5894.                HLT
  5895.                DB    "(C) 1995 "
  5896.                DB    "Ciriaco García de Celis - "
  5897.                DB    "Valladolid/Spain"
  5898.                DB    0
  5899. PINFOBOOT      EQU   74h       ; offset físico del área con información
  5900. bootp          InfoBoot <>     ; información del BOOT
  5901.                DB    126 DUP (0)
  5902.                DW    0AA55h         ; para el DOS, por si es de 256 bytes
  5903.                DB    254 DUP (0)
  5904.                DW    0AA55h         ; para el DOS, por si es de 512 bytes
  5905.  
  5906.                ; --- Información IOCTL por defecto.
  5907.  
  5908. info_drv120    DB    4, 1              ; sectores iguales / tipo 1.2M
  5909.                DW    2, 13118          ; detecta cambio / nº pistas
  5910.                DB    0                 ; tipo de soporte
  5911.                DW    128               ; BPB: bytes por sector
  5912.                DB    8                 ; BPB: sectores por cluster
  5913.                DW    1                 ; BPB: sectores reservados
  5914.                DB    1                 ; BPB: número de FATs
  5915.                DW    132               ; BPB: entradas en el raíz
  5916.                DW    13118             ; BPB: nº total de sectores
  5917.                DB    0FAh              ; BPB: descriptor de medio
  5918.                DW    20                ; BPB: sectores por FAT
  5919.                DW    1, 1              ; BPB: sectores pista / cabezas
  5920.                DB    14 DUP (0)        ; BPB: restantes campos
  5921.  
  5922. info_drv144    DB    4, 7              ; sectores iguales / tipo 1.44M
  5923.                DW    2, 15776          ; detecta cambio / nº pistas
  5924.                DB    0                 ; tipo de soporte
  5925.                DW    128               ; BPB: bytes por sector
  5926.                DB    8                 ; BPB: sectores por cluster
  5927.                DW    1                 ; BPB: sectores reservados
  5928.                DB    1                 ; BPB: número de FATs
  5929.                DW    156               ; BPB: entradas en el raíz
  5930.                DW    15776             ; BPB: nº total de sectores
  5931.                DB    0FAh              ; BPB: descriptor de medio
  5932.                DW    24                ; BPB: sectores por FAT
  5933.                DW    1, 1              ; BPB: sectores pista / cabezas
  5934.                DB    14 DUP (0)        ; BPB: restantes campos
  5935.  
  5936. info_drv288    DB    4, 9              ; sectores iguales / tipo 2.88M
  5937.                DW    2, 31552          ; detecta cambio / nº pistas
  5938.                DB    0                 ; tipo de soporte
  5939.                DW    128               ; BPB: bytes por sector
  5940.                DB    16                ; BPB: sectores por cluster
  5941.                DW    1                 ; BPB: sectores reservados
  5942.                DB    1                 ; BPB: número de FATs
  5943.                DW    156               ; BPB: entradas en el raíz
  5944.                DW    31552             ; BPB: nº total de sectores
  5945.                DB    0FAh              ; BPB: descriptor de medio
  5946.                DW    24                ; BPB: sectores por FAT
  5947.                DW    1, 1              ; BPB: sectores pista / cabezas
  5948.                DB    14 DUP (0)        ; BPB: restantes campos
  5949.  
  5950. ; ------------ Mensajes de instalación.
  5951.  
  5952. programa_txt   DB    13,10,"2MGUI 1.0 ",13,10,0
  5953.  
  5954. instalado_txt  DB    "  Instalado en unidad(es) "
  5955. tabla_letras1  DB    "A:         ",13,10,255
  5956.                DB    "  Installed on drive(s) "
  5957. tabla_letras2  DB    "A:         ",13,10,0
  5958.  
  5959. errxtdma_txt   DB    "  - Nota:    Sistema PC/XT, soportado sólo modo DMA.",13,10,255
  5960.                DB    "  - Note:    PC/XT system, supported only DMA mode.",13,10,0
  5961.  
  5962. erremsins_txt  DB    "  - Nota:    No ha sido posible utilizar memoria EMS.",13,10,255
  5963.                DB    "  - Note:    It isn't possible to use EMS memory.",13,10,0
  5964.  
  5965. erremsdma_txt  DB    "  - Nota:    Sólo se puede utilizar EMS en modo /NODMA.",13,10,255
  5966.                DB    "  - Note:    To use EMS is only possible in /NODMA mode.",13,10,0
  5967.  
  5968. mal_dos_txt    DB    "  - Error:   Necesario DOS 3.30 o posterior.",13,10,255
  5969.                DB    "  - Error:   Needs DOS 3.30 or above.",13,10,0
  5970.  
  5971. mal_bios_txt   DB    "  - Error:   No puedo detectar el tipo de las unidades. Instale 2M-?BIOS antes.",13,10,255
  5972.                DB    "  - Error:   Impossible to detect drive types. Please install 2M-?BIOS before.",13,10,0
  5973.  
  5974. mal_drv_txt    DB    "  - Error:   Necesaria(s) unidad(es) de alta densidad.",13,10,255
  5975.                DB    "  - Error:   Needs high-density floppy drive(s).",13,10,0
  5976.  
  5977. ya_ins_txt     DB    "  - Error:   Programa ya instalado en memoria.",13,10,255
  5978.                DB    "  - Error:   Program already loaded on memory.",13,10,0
  5979.  
  5980. dma_front_txt  DB    "  - Consejo: Modifique la ubicación en memoria de este programa  (variando  el",13,10
  5981.                DB    "             orden de instalación de dispositivos) o, alternativamente, pruebe",13,10
  5982.                DB    "             a instalarlo en modo NO-DMA.  El motivo es economizar memoria, ya",13,10
  5983.                DB    "             que se cruza una frontera de DMA.  No obstante, el programa puede",13,10
  5984.                DB    "             funcionar perfectamente así, ocupando más memoria.",13,10,255
  5985.                DB    "  - Advice:  Modify the memory location of this utility  (variying  the  devices",13,10
  5986.                DB    "             installation order) or install the program in Non-DMA mode, to save",13,10
  5987.                DB    "             memory. The problem is that 2MGUI crosses a DMA frontier.  But this",13,10
  5988.                DB    "             program can work correctly in this way (taking more memory).",13,10,0
  5989.  
  5990. dma_poco_txt   DB    "  - Nota:    El buffer DMA de su controlador de memoria es demasiado pequeño,",13,10
  5991.                DB    "             auméntelo a 13 (1.44M) ó 25 (2.88M) Kbytes.",255
  5992.                DB    "  - Note:    The DMA buffer of your memory manager is too small; set it",13,10
  5993.                DB    "             to 13 (1.44M) or 25 (2.88M) Kbytes.",0
  5994.  
  5995. emm_qemm_txt   DB    " En su controlador de",13,10
  5996.                DB    "             memoria (QEMM) basta que le añada la opción DMA=13 ó DMA=25.",13,10,255
  5997.                DB    "  With your memory manager (QEMM) you must add",13,10
  5998.                DB    "             to it a DMA=13 or DMA=25 switch.",13,10,0
  5999.  
  6000. nocabe_txt     DB    "  Instalación imposible:",13,10
  6001.                DB    "      Ya hay 64 programas residentes con la misma técnica.",13,10,255
  6002.                DB    "  Unable to install:",13,10
  6003.                DB    "      There are already 64 TSR's with the same technique.",13,10,0
  6004.  
  6005. err_sintax_txt DB    "  - Error de sintaxis o parámetro fuera de rango.",13,10,255
  6006.                DB    "  - Syntax error or parameter out of range.",13,10,0
  6007. pet_ayuda_txt  DB    "    Ejecute 2MGUI /? si desea obtener ayuda.",13,10,255
  6008.                DB    "    Execute 2MGUI /? to obtain more help.",13,10,0
  6009.  
  6010. no_ins_txt     DB    "  - Error: Instale este programa primero en CONFIG.SYS",13,10,255
  6011.                DB    "  - Error: First, install this program in CONFIG.SYS",13,10,0
  6012.  
  6013. err_mem_txt    DB    "  - Error: memoria insuficiente.",13,10,255
  6014.                DB    "  - Error: insufficient memory.",13,10,0
  6015.  
  6016. ; ------------ Mensajes varios.
  6017.  
  6018. limpia_txt     DB    13,"                                                                              ",13,0
  6019.  
  6020. lin_txt        DB    "───────────────────────────────────────────────────────────────────────────────",13,10,0
  6021.  
  6022. err_prot_txt   DB    13,"  - Disco protegido contra escritura.",13,10,255
  6023.                DB    13,"  - Write protected disk error.",13,10,0
  6024.  
  6025. no_prep_txt    DB    13,"  - Unidad no preparada.",13,10,255
  6026.                DB    13,"  - Drive not ready.",13,10,0
  6027.  
  6028. mal_dens_txt   DB    13,"  - Anomalía general. ¿Densidad incorrecta?.",13,10,255
  6029.                DB    13,"  - General failure. Incorrect density?.",13,10,0
  6030.  
  6031. mal_unidad_txt DB    "  - La unidad no existe o no es de alta densidad.",13,10,255
  6032.                DB    "  - Diskette drive doesn't exist or it isn't high-density.",13,10,0
  6033.  
  6034. dh_test_txt    DB    "  - El parámetro /DH no puede indicarse junto a /TEST.",13,10,255
  6035.                DB    "  - The /DH switch can not be used with /TEST.",13,10,0
  6036.  
  6037. pconfig_txt    DB    "  - El parámetro /NODMA sólo puede indicarse en CONFIG.SYS o con /TEST; y ",13,10
  6038.                DB    "    el parámetro /EMS sólo puede indicarse en CONFIG.SYS y junto a /NODMA.",13,10,255
  6039.                DB    "  - The /NODMA switch can only be used in CONFIG.SYS or with /TEST; and",13,10
  6040.                DB    "    the /EMS switch can only be used in CONFIG.SYS and with /NODMA.",13,10,0
  6041.  
  6042. crlf_txt       DB    13,10,0
  6043.  
  6044. ; ------------ Informe de unidades.
  6045.  
  6046. hay_2mgui_txt  DB    13,10
  6047.                DB    "2MGUI 1.0 ya instalado en memoria.",13,10,255
  6048.                DB    13,10
  6049.                DB    "2MGUI 1.0 already installed in memory.",13,10,0
  6050. hay_en_txt     DB    "  - Nueva unidad ",255
  6051.                DB    "  - New drive ",0
  6052. nueva_u        DB    "E: ",0
  6053. hay2_txt       DB    " (unidad física ",255
  6054.                DB    " (physical drive ",0
  6055. vieja_u        DB    "A"
  6056.                DB    ":)",13,10,0
  6057. gap_txt        DB    "  - GAP anti-FIFO de",255
  6058.                DB    "  - Anti-FIFO GAP of",0
  6059. dma1_txt       DB    " bytes y modo ",255
  6060.                DB    " bytes and ",0
  6061. dmano_txt      DB    "NO-",255,"non-",0
  6062. dma2_txt       DB    "DMA.",13,10,255
  6063.                DB    "DMA mode.",13,10,0
  6064.  
  6065. buffer_ems_txt DB    "  - Buffer interno ubicado en memoria EMS.",13,10,255
  6066.                DB    "  - Internal buffer placed in EMS memory.",13,10,0
  6067.  
  6068. cache_off_txt  DB    "  - Escritura retardada desactivada.",13,10,255
  6069.                DB    "  - Delayed-write disabled.",13,10,0
  6070.  
  6071. sopdr_on_txt   DB    "  - Soporte para DISKCOPY DR-DOS y Novell DOS activo.",13,10,255
  6072.                DB    "  - DR-DOS and Novell DOS DISKCOPY support enabled.",13,10,0
  6073.  
  6074. ; ------------ Mensajes de formateo.
  6075.  
  6076. no_2mgui_txt   DB    13,10,"2MGUI 1.0",13,10
  6077.                DB    "  - Error: La unidad indicada no es un dispositivo 2MGUI.",13,10,255
  6078.                DB    13,10,"2MGUI 1.0",13,10
  6079.                DB    "  - Error: Drive indicated does not is a 2MGUI device.",13,10,0
  6080.  
  6081. mucha_fat_txt  DB    13,10,"2MGUI 1.0",13,10
  6082.                DB    "  - Error: Memoria insuficiente para una FAT tan grande.",13,10,255
  6083.                DB    13,10,"2MGUI 1.0",13,10
  6084.                DB    "  - Error: Insufficient memory for so big a FAT.",13,10,0
  6085.  
  6086. fmtm1_txt      DB    13,10,"2MGUI 1.0 Formateando",255
  6087.                DB    13,10,"2MGUI 1.0 Formatting",0
  6088. fmtm2_txt      DB    " bytes por pista en ",255
  6089.                DB    " bytes per track in ",0
  6090. fmtm3_txt      DB    ": ",0
  6091. fmtm4_txt      DB    "   (ESC Salir)",13,10,255
  6092.                DB    "   (ESC Aborts)",13,10,0
  6093. fmtm5_txt      DB    "  Inicializando disquete de ",255,"  Initializing ",0
  6094. fmtm6_txt      DB    " con",255," diskette with",0
  6095. fmtm7_txt      DB    "K",13,10,0
  6096.  
  6097. pausaf_txt     DB    "  Pulsa INTRO para formatear u otra tecla para terminar...",255
  6098.                DB    "  Press ENTER key to begin format or another key to exit...",0
  6099.  
  6100. abortado_txt   DB    13,"  - Formateo interrumpido por el usuario.",13,10,255
  6101.                DB    13,"  - Format aborted by user.              ",13,10,0
  6102.  
  6103. mucha_pis_txt  DB    13,"  - La unidad no soporta tanta capacidad en la pista.",13,10,255
  6104.                DB    13,"  - This drive doesn't support so big a track.",13,10,0
  6105.  
  6106. mal_sys_txt    DB    13,"  - Fatal: fallo en áreas del sistema.",13,10,255
  6107.                DB    13,"  - Fatal: failure on system areas.",13,10,0
  6108.  
  6109. cil_txt        DB    13,"  Cilindro ",255,13,"  Cylinder ",0
  6110. cab_txt        DB    " Cara",255," Side",0
  6111. p_txt          DB    "       ",0
  6112. f_txt          DB    8,8,8,8,8,"[F--]",0
  6113. w_txt          DB    8,8,8,8,8,"[-X-]",0
  6114. v_txt          DB    8,8,8,8,8,"[--V]",0
  6115. error_txt      DB    13,10,"Error",0
  6116.  
  6117. t_drvs         DW    t360, t1200, t720, t1440, t2880, t2880
  6118. t360           DB    "360K",0
  6119. t1200          DB    "1.2M",0
  6120. t720           DB    "720K",0
  6121. t1440          DB    "1.44M",0
  6122. t2880          DB    "2.88M",0
  6123.  
  6124. capacidad1_txt DB    13,"  Espacio bruto en disco de",255
  6125.                DB    13,"  Crude disk space is",0
  6126. capacidad2_txt DB    " bytes.",13,10,0
  6127.  
  6128. etiq_txt       DB    "  Etiqueta de volúmen ",255
  6129.                DB    "  Volume label ",0
  6130.  
  6131. err_info_txt   DB    "  - Retire e introduzca el disco antes de usarlo.",13,10,255
  6132.                DB    "  - Extract and reinsert the disk before using it.",13,10,0
  6133.  
  6134. if1_txt        DB    " ficheros permitidos en el raíz.",13,10,255
  6135.                DB    " file capacity of root directory.",13,10,0
  6136. if2_txt        DB    " unidades de asignación.",13,10,255
  6137.                DB    " total clusters on disk.",13,10,0
  6138. if3_txt        DB    " bytes por unidad de asignación.",13,10,255
  6139.                DB    " bytes per cluster.",13,10,0
  6140. if4_txt        DB    " bytes totales en el disco.",13,10,255
  6141.                DB    " total bytes on disk.",13,10,0
  6142. if5_txt        DB    " bytes en sectores defectuosos.",13,10,255
  6143.                DB    " bytes in bad tracks.",13,10,0
  6144. if6_txt        DB    " bytes disponibles en el disco.",13,10,255
  6145.                DB    " bytes available on disk.",13,10,0
  6146.  
  6147. ; ------------ Mensajes para el test.
  6148.  
  6149. test_txt1      DB    13,10,10,"2MGUI 1.0: TEST DE CAPACIDAD Y CALIDAD DE LA UNIDAD                (ESC Salir)",13,10,255
  6150.                DB    13,10,10,"2MGUI 1.0: DISKETTE DRIVE MAXIMUM CAPACITY AND QUALITY TEST       (ESC Aborts)",13,10,0
  6151.  
  6152. test_txt_t     DB    "  - Introduzca un disco que PERDERA TODOS LOS DATOS y pulse una tecla.",255
  6153.                DB    "  - Insert a disk which will LOSE ALL DATA and press any key.",0
  6154.  
  6155. test_dma_txt   DB    "  NOTA: El test puede producir resultados absurdos si su sistema o la",13,10
  6156.                DB    "    configuración del mismo no soporta el acceso en modo NO-DMA.",13,10,255
  6157.                DB    "  NOTE: This test may return nonsense results if your hardware or your",13,10
  6158.                DB    "    system configuration does not support Non-DMA diskette access mode.",13,10,0
  6159.  
  6160. test_bdma_txt  DB    "  NOTA: El buffer de DMA de su PC es demasiado pequeño; cambie la configuración",13,10
  6161.                DB    "    del controlador de memoria si se cuelga o si aparece alguna excepción.  Con",13,10
  6162.                DB    "    QEMM basta añadir DMA=14 (1.44M) ó DMA=28 (2.88M) [algo más de lo normal].",13,10,255
  6163.                DB    "  NOTA: The maximum DMA buffer on your PC is too small;  if the PC hangs during",13,10
  6164.                DB    "    the test or the EMM reports a exception, set a bigger buffer. With QEMM you",13,10
  6165.                DB    "    can add a DMA=14 (1.44M) or a DMA=28 (2.88M) [a little more than normal].",13,10,0
  6166.  
  6167. test_txt2      DB    13,"  Probando ",255
  6168.                DB    13,"  Testing ",0
  6169. test_txt3      DB    " bytes en ",255
  6170.                DB    " bytes in ",0
  6171. test_txt4      DB    ": [Disco de ",255
  6172.                DB    ": [",0
  6173. test_txt5      DB    "]      ",8,8,8,8,8,8,255
  6174.                DB    " diskette]      ",8,8,8,8,8,8,0
  6175.  
  6176. test_r_txt11c  DB    13,"  - Con ",255
  6177.                DB    13,"  - With ",0
  6178. test_r_txt11s  DB    13,"  - Sin ",255
  6179.                DB    13,"  - Without ",0
  6180.  
  6181. test_r_txt12   DB    "DMA y bits ",255
  6182.                DB    "DMA and ",0
  6183. test_r_txt12i  DB    "idénticos",255
  6184.                DB    "identic bits",0
  6185. test_r_txt12d  DB    "aleatorios",255
  6186.                DB    "random bits",0
  6187. test_r_txt13   DB    " máxima capacidad por pista:",9,255
  6188.                DB    " maximum size in each track:",9,0
  6189. test_r_txt14   DB    " bytes.",13,10,0
  6190. test_r_txt15   DB    "    Mínimo posible GAP anti-FIFO detectado:",9,9,9,255
  6191.                DB    "    Possible minimum anti-FIFO GAP detected:",9,9,9,0
  6192.  
  6193. aviso_gap_txt  DB    "  AVISO:",13,10
  6194.                DB    "  - Su controladora precisa un GAP anti-FIFO  mayor del establecido por defecto",13,10
  6195.                DB    "    por el programa; indíquelo explícitamente con la opción /G al instalarlo.",13,10,255
  6196.                DB    "  IMPORTANT:",13,10
  6197.                DB    "  - Your diskette controller needs a bigger anti-FIFO GAP than default settings",13,10
  6198.                DB    "    for program; set it with /G switch during program installation.",13,10,0
  6199.  
  6200. test_res_txt3  DB    "  NOTAS SOBRE LOS PARAMETROS /B Y /G:",13,10
  6201.                DB    "  - El valor máximo soportado por /B para lograr más capacidad en los disquetes",13,10
  6202.                DB    "    será normalmente la capacidad máxima en la pista MENOS el GAP anti-FIFO (20",13,10
  6203.                DB    "    bytes por defecto).  Es  decir,  reste 20 bytes de la capacidad de la pista",13,10
  6204.                DB    "    para obtener el valor máximo de /B.  Ajustando  también dicho GAP con /G se",13,10
  6205.                DB    "    puede obtener aún más capacidad. Cuidado: /G varía ligeramente con EMM386.",13,10
  6206.                DB    "  - Use siempre los datos del test de PEOR resultado de todos los realizados.",13,10
  6207.                DB    "  - Recuerde que estos disquetes serán *estropeados* al ser  ESCRITOS por otras",13,10
  6208.                DB    "    unidades que admitan menos capacidad, aunque podrán LEERSE sin problemas.",13,10
  6209.                DB    "  - No utilice los valores límites si quiere que el programa funcione.",13,10,255
  6210.                DB    "  NOTES ABOUT /B AND /G SWITCHES:",13,10
  6211.                DB    "  - The maximum value supported by /B switch to get more disk capacity, will be",13,10
  6212.                DB    "    usually the maximum size per track but SUBSTRACTING anti-FIFO GAP (20 bytes",13,10
  6213.                DB    "    by default).  This means that you have to substract 20 bytes to the maximum",13,10
  6214.                DB    "    track size to obtain /B value. Adjusting also this GAP with /G switch, it's",13,10
  6215.                DB    "    also possible to get more capacity. Warning: /G vary slightly with EMM386.",13,10
  6216.                DB    "  - You must use always the results of WORST test of all performed.",13,10
  6217.                DB    "  - Remember that this diskettes will be *damaged* when WRITTING them on other",13,10
  6218.                DB    "    drives with less capacity, although they can be READED without problems.",13,10
  6219.                DB    "  - Choosing minimum/maximum limits for values, the program may not work.",13,10,0
  6220.  
  6221. disco_def_txt  DB    "  - Nota: ¡Este disco quizá tenga defectuosa la pista 0!.",13,10,255
  6222.                DB    "  - Note: your diskette is perhaps damaged on track 0!",13,10,0
  6223.  
  6224. test_res_mal   DB    "  - Su unidad de disco es pésima y no admite siquiera la capacidad mínima",13,10
  6225.                DB    "    que necesita el programa. Cómprese otra mejor y, mientras tanto, no",13,10
  6226.                DB    "    escriba sobre los discos 2MGUI que le pasen otras personas.",13,10,255
  6227.                DB    "  - Your  diskette  drive  is very bad and doesn't support the minimum size",13,10
  6228.                DB    "    needed by this program.  You must buy a better drive and, meanwhile, do",13,10
  6229.                DB    "    not write on 2MGUI disks that other people send to you (only read!).",13,10,0 ;;;
  6230.  
  6231. spin0_txt      DB    "  TEST DE VELOCIDAD DE ROTACION:",13,10,255
  6232.                DB    "  ROTATION SPEED TEST:",13,10,0
  6233.  
  6234. spin1_txt      DB    13,"  - Período de rotación: ",255
  6235.                DB    13,"  - Rotation period: ",0
  6236. spin2_txt      DB    " ms (",0
  6237. spin3_txt      DB    ")  [ESC-Fin]",255,")  [ESC-End]",0
  6238.  
  6239. spind_txt      DB    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"; con una desviación de ",255
  6240.                DB    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"; with a shift of ",0
  6241.  
  6242. spinf1_txt     DB    " ms",13,10,"    sobre al valor esperado de ",255
  6243.                DB    " ms from the",13,10,"    expected value of ",0
  6244. spinf2_txt     DB    " ms (unidad de ",255
  6245.                DB    " ms (",0
  6246. spinf3_txt     DB    " calidad).",13,10,255
  6247.                DB    " quality drive).",13,10,0
  6248.  
  6249. spinf_calidad  DW    100
  6250.                DW    c_altisima
  6251.                DW    250
  6252.                DW    c_alta
  6253.                DW    500
  6254.                DW    c_mediana
  6255.                DW    750
  6256.                DW    c_mala
  6257.                DW    1000
  6258.                DW    c_pesima
  6259.                DW    0
  6260.                DW    c_pesima
  6261. c_altisima     DB    "muy elevada",255,"very high",0
  6262. c_alta         DB    "alta",255,"high",0
  6263. c_mediana      DB    "mediana",255,"medium",0
  6264. c_mala         DB    "baja",255,"bad",0
  6265. c_pesima       DB    "pésima",255,"very bad",0
  6266.  
  6267. spine_txt      DB    13,"    Nota: ha habido algún problema calculando el período de rotación.",13,10,255
  6268.                DB    13,"    Note: it have been some problem computing rotation period.",13,10,0
  6269.  
  6270. test_esc_txt   DB    13,"  - TEST interrumpido por el usuario.",13,10,255
  6271.                DB    13,"  - TEST aborted by user.",13,10,0
  6272.  
  6273. disco_mal_txt  DB    "  RECUERDE QUE EL DISCO DE PRUEBA ESTA INSERVIBLE: DEBERA FORMATEARLO.",13,10,255
  6274.                DB    "  REMEMBER THAT TEST DISK IS NOW DAMAGED: YOU MUST FORMAT IT BEFORE USE.",13,10,0
  6275.  
  6276. ; ------------ Ayuda.
  6277.  
  6278. ayuda_txt      LABEL BYTE
  6279. DB 13,10,10
  6280. DB "           2M GUINNESS 1.0 - ACCESO DIRECTO A DISCO SIN CONTROLADORA",13,10
  6281. DB "   (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática",13,10
  6282. DB "   C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10
  6283. DB 10
  6284. DB "   2MGUI [U:]  [/DD] [/DH] [/ED] [/T:n] [/R:n] [/C:n] [/S:n] [/F:n] [/N] [/K]",13,10
  6285. DB 10
  6286. DB "   Este programa obtiene *toda* la capacidad de los discos antes de formatear;",13,10
  6287. DB " pudiendo incluso adaptarse a la velocidad de la unidad para obtener aún más.",13,10
  6288. DB 10
  6289. DB "   Instálelo primero en el  CONFIG.SYS  con una línea como «DEVICE=2MGUI.EXE»;",13,10
  6290. DB " a raíz de ello se crearán tantas nuevas letras como unidades de alta densidad",13,10
  6291. DB " haya en el sistema.  Los discos formateados por este programa sólo podrán ser",13,10
  6292. DB " accedidos en esas nuevas unidades, que también soportan discos estándar (y 2M",13,10
  6293. DB " si 2M está instalado).  Es más, este programa permite utilizar discos 2M bajo",13,10
  6294. DB " OS/2 en esas nuevas unidades. Al conmutar entre dichas unidades y las físicas",13,10
  6295. DB " se simula un cambio de disco automático (y no se pide nuevo disco).",13,10
  6296. DB 10
  6297. DB "   Para formatear los nuevos discos, ejecute 2MGUI indicando la unidad que les",13,10
  6298. DB " soporta. Por defecto se utiliza alta densidad; /DD selecciona doble densidad,",13,10
  6299. DB " /DH formatea 1/3 en alta densidad y 2/3 en doble (sólo discos de 360K)  y /ED",13,10
  6300. DB " selecciona 2.88M; /T indica el nº de pistas  (80-86, por defecto 82),  /R  el",13,10
  6301. DB " nº mínimo de ficheros en el raíz (1-240); /C el tamaño de cluster (128-16384)",13,10
  6302. DB " y /S el de sector (128-512), ambos han de ser potencia de 2; /F el nº de FATs",13,10
  6303. DB " (1-2); /N no verifica y /K evita las pausas.",13,10
  6304. DB "                                                      (1/5)  [PULSA UNA TECLA]",1
  6305. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10,10
  6306. DB "                                 ┌───────────┬───────────┬────────────┐",13,10
  6307. DB "                                 │   Doble   │   Alta    │ Extraalta  │",13,10
  6308. DB " ┌───────────────────────────────┼───────────┼───────────┼────────────┼──────┐",13,10
  6309. DB " │ Récord absoluto previo a 2M   │  820.0 Kb │ 1394.0 Kb │     --     │      │",13,10
  6310. DB " │ Capacidad máxima 2M (2MF /M)  │  902.0 Kb │ 1558.0 Kb │     --     │ 5.25 │",13,10
  6311. DB " │ Capacidad mínima de 2MGUI     │  976.6 Kb │ 1639.8 Kb │ 1203.1 Kb# │ (5¼) │",13,10
  6312. DB " │ Capacidad límite física (82p) │ 1001.0 Kb │ 1668.2 Kb │ 1228.8 Kb# │      │",13,10
  6313. DB " ├───────────────────────────────┼───────────┼───────────┼────────────┼──────┤",13,10
  6314. DB " │ Récord absoluto previo a 2M   │  984.0 Kb │ 1722.0 Kb │ 2880.0 Kb  │      │",13,10
  6315. DB " │ Capacidad máxima 2M (2MF /M)  │ 1066.0 Kb │ 1886.0 Kb │ 3772.0 Kb* │  3.5 │",13,10
  6316. DB " │ Capacidad mínima de 2MGUI     │ 1176.0 Kb │ 1972.0 Kb │ 3944.0 Kb* │ (3½) │",13,10
  6317. DB " │ Capacidad límite física (82p) │ 1201.2 Kb │ 2002.0 Kb │ 4003.9 Kb  │      │",13,10
  6318. DB " └───────────────────────────────┴───────────┴───────────┴────────────┴──────┘",13,10
  6319. DB "      (#) Discos de 360K con formato /DH. (*) No probado. En la lista aparecen",13,10
  6320. DB "      SOLO los formatos soportados por casi todas las unidades y ordenadores.",13,10
  6321. DB 10
  6322. DB "   Los disquetes 2MGUI utilizan una tecnología totalmente nueva,  que  permite",13,10
  6323. DB " acceder directamente a la unidad, con una técnica ideada por Jesús Arias, sin",13,10
  6324. DB " emplear -en la práctica- la controladora de disquetes.   En escritura son más",13,10
  6325. DB " lentos que un disco normal, pero leyendo lo superan. El consumo de memoria de",13,10
  6326. DB " este programa (17 Kb en 1.44M) es elevado.  Estos discos son casi tan seguros",13,10
  6327. DB " como los 2M normales o los 2MF/M, pero su arquitectura no es la mejor de cara",13,10
  6328. DB " a su empleo bajo sistemas multitarea.  Funcionan en la mayoría de PC, XT y AT",13,10
  6329. DB " con controladora y unidades de alta densidad.",13,10
  6330. DB "                                                      (2/5)  [PULSA UNA TECLA]",1
  6331. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10,10
  6332. DB "        ────────────────── OTRAS OPCIONES DEL PROGRAMA SON ───────────────────",13,10
  6333. DB " /Q     Hace un formateo rápido de las dos primeras pistas;  útil para cambiar",13,10
  6334. DB "        las características lógicas de un disco no defectuoso ya formateado.",13,10
  6335. DB " /L=et  Establece la etiqueta de volúmen del disco (máximo 11 caracteres).  Se",13,10
  6336. DB "        admiten mayúsculas y minúsculas.",13,10
  6337. DB " /V=et  Establece una etiqueta de volúmen incremental en series de discos  (es",13,10
  6338. DB "        preciso que acabe en número).",13,10
  6339. DB " /TEST  Obtiene con exactitud total la capacidad admitida por la unidad que se",13,10
  6340. DB "        indique, y determina la velocidad de rotación de la misma. El disco no",13,10
  6341. DB "        necesita estar formateado y los datos que contuviera se pierden  (test",13,10
  6342. DB "        destructivo). Puede acompañarse de /DD ó /ED para elegir densidad; por",13,10
  6343. DB "        defecto se realiza el test en alta densidad. También se admite /NODMA.",13,10
  6344. DB " /B=n   Fuerza el formateo con una determinada capacidad por pista  (quizá  la",13,10
  6345. DB "        obtenida por la prueba anterior).  Así,  se  aprovechará totalmente la",13,10
  6346. DB "        capacidad de una unidad concreta. Estos disquetes podrán ser LEIDOS en",13,10
  6347. DB "        otras disqueteras, pero su ESCRITURA en unidades peores los dañará.",13,10
  6348. DB " /G=n   Selecciona el valor del GAP anti-FIFO.  La capacidad bruta de la pista",13,10
  6349. DB "        es la suma de este valor (por defecto, 20) más el indicado con /B:  un",13,10
  6350. DB "        menor GAP permite aumentar /B pero disminuye la seguridad.",13,10
  6351. DB " /M=n   Elige el número de pistas de alta densidad en el formato /DH  (28  por",13,10
  6352. DB "        defecto, equivalentes a la primera tercera parte del disco).",13,10
  6353. DB " /DRON  Activa el soporte para DISKCOPY inverso (lo contrario es /DROFF).  Use",13,10
  6354. DB "        solo /DRON o /DROFF si DISKCOPY recalibrara en cada pista.  /DRON está",13,10
  6355. DB "        activo por defecto en DR-DOS 6 y Novell DOS 7.",13,10
  6356. DB "                                                      (3/5)  [PULSA UNA TECLA]",1
  6357. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10,10
  6358. DB " /DWOFF Desactiva la caché de escritura retardada (lo contrario es /DWON). Por",13,10
  6359. DB "        defecto, la escritura retardada está activa. Inhíbala si detecta algún",13,10
  6360. DB "        conflicto con otro software de sistema, si bien sería muy raro. Copiar",13,10
  6361. DB "        discos (DISKCOPY) sin escritura retardada puede representar horas.",13,10
  6362. DB " /X=n   Valor para desplazar el comienzo físico de una pista respecto a la que",13,10
  6363. DB "        le precede, al conmutar de cabezal,  expresado  en  grados (0-359°) de",13,10
  6364. DB "        longitud angular de la pista (sector sliding /X), por defecto 55°.",13,10
  6365. DB " /Y=n   Similar al anterior pero al conmutar de cilindro, por defecto 90°. No",13,10
  6366. DB "        altere /X ni /Y si no conoce su significado: incide en el rendimiento.",13,10
  6367. DB " /NODMA Desactiva el funcionamiento en modo DMA. En modo DMA, QEMM necesita el",13,10
  6368. DB "        parámetro DMA=13 (1.44M) ó DMA=25 (2.88M), aunque EMM386 no.  Se puede",13,10
  6369. DB "        evitar esto (o el cruce de una frontera de DMA) indicando esta opción:",13,10
  6370. DB "        2MGUI permite operar en los AT sin DMA, aunque así es menos compatible",13,10
  6371. DB "        con ciertas configuraciones (cuando funciona, la seguridad es total).",13,10
  6372. DB " /EMS   Sólo admitido junto a /NODMA, utiliza EMS para consumir sólo 5 Kb.",13,10
  6373. DB 10
  6374. DB " Derechos de copia:",13,10
  6375. DB " ──────────────────",13,10
  6376. DB " La tecnología empleada por 2MGUI y el formato de disco resultante son dominio",13,10
  6377. DB " público. Cualquier patente posterior de la técnica de acceso a pistas físicas",13,10
  6378. DB " completas, realizada en cualquier país, carecerá de validez.  Este  programa,",13,10
  6379. DB " sin embargo, sí es Copyright (C) de su autor. Puede ser libre y gratuitamente",13,10
  6380. DB " distribuído; la condición de registro es la del paquete 2M (enviar la tarjeta",13,10
  6381. DB " postal al autor).",13,10
  6382. DB "                                                      (4/5)  [PULSA UNA TECLA]",1
  6383. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10,10
  6384. DB " Ultimas consideraciones:",13,10
  6385. DB " ────────────────────────",13,10
  6386. DB " - Se puede ejecutar DISKCOPY sobre una unidad 2MGUI,  sobre cualquier tipo de",13,10
  6387. DB "   disco, siempre que el disco destino esté ya formateado, y tenga exactamente",13,10
  6388. DB "   las mismas características físicas y tamaño que el origen.  El DISKCOPY del",13,10
  6389. DB "   MS-DOS (no del DR-DOS)  falla  en la primera ejecución sobre un nuevo disco",13,10
  6390. DB "   cuando no es del mismo tipo que el accedido por última vez;  esto es porque",13,10
  6391. DB "   no soporta que un controlador de dispositivo modifique, dinámicamente,  sus",13,10
  6392. DB "   características físicas. Si DISKCOPY da error, vuelva a ejecutarlo; en todo",13,10
  6393. DB "   caso, es mejor hacer antes un DIR sobre la unidad, para evitar problemas.",13,10
  6394. DB 10
  6395. DB " - 2MGUI realiza una escritura retardada (sólo en discos 2MGUI). El usuario no",13,10
  6396. DB "   debería retirar el disco,  aunque  haya aparecido ya el prompt del sistema,",13,10
  6397. DB "   hasta que haya transcurrido algo más de medio segundo.",13,10
  6398. DB 10
  6399. DB " Importante:",13,10
  6400. DB " ───────────",13,10
  6401. DB " - Bajo Windows 3 las operaciones sobre disquetes 2MGUI en el administrador de",13,10
  6402. DB "   archivos dejan colapsado el sistema.  Sin  embargo,  aunque  el puntero del",13,10
  6403. DB "   ratón no obedezca y el teclado parezca estar bloqueado,  el sistema no está",13,10
  6404. DB "   necesariamente colgado. Espere unos segundos antes de resetear.  Windows 95",13,10
  6405. DB "   es compatible con 2MGUI sólo en las sesiones de auténtico MS-DOS.",13,10
  6406. DB " - Es conveniente indicar BUFFERS=40 en CONFIG.SYS para mayor rendimiento.",13,10
  6407. DB 255
  6408.  
  6409. DB 13,10,10
  6410. DB "        2M GUINNESS 1.0 - DIRECT DISK DRIVE ACCESS BYPASSING CONTROLLER",13,10
  6411. DB "  (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática.",13,10
  6412. DB "   C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10
  6413. DB 10
  6414. DB "   2MGUI [U:] [/DD] [/DH] [/ED] [/T:n] [/R:n] [/C:n] [/S:n] [/F:n] [/N] [/K]",13,10
  6415. DB 10
  6416. DB "   This program gets *all* disk's size available before format process;  it is",13,10
  6417. DB " also capable of fitting itself at disk drive speed in order to get more size.",13,10
  6418. DB 10
  6419. DB "   You must load it first in  CONFIG.SYS  with a line like «DEVICE=2MGUI.EXE»;",13,10
  6420. DB " from this moment,  there  will  appear as many new disk drive letters as high",13,10
  6421. DB " density drives installed on the system.  New  disks formatted by this program",13,10
  6422. DB " only can be used on such new drives, which also support standard  disks  (and",13,10
  6423. DB " even 2M disks if 2M is loaded).  In fact, 2MGUI lets OS/2 support 2M disks in",13,10
  6424. DB " these new drives.  When changing from a new drive to the physical one or vice",13,10
  6425. DB " versa, a disk change is simulated (user won't be asked for new disk).",13,10
  6426. DB 10
  6427. DB "   To format new disks,  you can execute 2MGUI useing the drive which supports",13,10
  6428. DB " them. By default, high density is used; /DD selects double density, /DH makes",13,10
  6429. DB " 1/3 in high density and 2/3 in double density (only 360K disks) and /ED means",13,10
  6430. DB " 2.88M format; /T selects the number of tracks (80-86, 82 by default),  /R the",13,10
  6431. DB " minimum number of root files (1-240);  /C the cluster size (128-16384) and /S",13,10
  6432. DB " the sector size (128-512), both must be a power of 2;  /F the FATs (1-2),  /N",13,10
  6433. DB " turns verify off and /K skips keyboard pauses.",13,10
  6434. DB "                                                        (1/5)  [PRESS ANY KEY]",1
  6435. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"               ",13,10,10
  6436. DB "                                 ┌───────────┬───────────┬────────────┐",13,10
  6437. DB "                                 │  Double   │   High    │ Extra high │",13,10
  6438. DB " ┌───────────────────────────────┼───────────┼───────────┼────────────┼──────┐",13,10
  6439. DB " │ Absolute record before 2M     │  820.0 Kb │ 1394.0 Kb │     --     │      │",13,10
  6440. DB " │ Maximum 2M capacity (2MF /M)  │  902.0 Kb │ 1558.0 Kb │     --     │ 5.25 │",13,10
  6441. DB " │ Minimum 2MGUI capacity        │  976.7 Kb │ 1639.8 Kb │ 1203.1 Kb# │ (5¼) │",13,10
  6442. DB " │ Physical limit (82 tracks)    │ 1001.0 Kb │ 1668.2 Kb │ 1228.8 Kb# │      │",13,10
  6443. DB " ├───────────────────────────────┼───────────┼───────────┼────────────┼──────┤",13,10
  6444. DB " │ Absolute record before 2M     │  984.0 Kb │ 1722.0 Kb │ 2880.0 Kb  │      │",13,10
  6445. DB " │ Maximum 2M capacity (2MF /M)  │ 1066.0 Kb │ 1886.0 Kb │ 3772.0 Kb* │  3.5 │",13,10
  6446. DB " │ Minimum 2MGUI capacity        │ 1176.0 Kb │ 1972.0 Kb │ 3944.0 Kb* │ (3½) │",13,10
  6447. DB " │ Physical limit (82 tracks)    │ 1201.2 Kb │ 2002.0 Kb │ 4003.9 Kb  │      │",13,10
  6448. DB " └───────────────────────────────┴───────────┴───────────┴────────────┴──────┘",13,10
  6449. DB "    (#) 360K diskettes with /DH format.  (*) Not tested.  Here are listed ONLY",13,10
  6450. DB "    those disk formats supported by most diskette drives and computer systems.",13,10
  6451. DB 10
  6452. DB "   2MGUI  disks  use  a  completely  new technology to access a diskette drive",13,10
  6453. DB " directly,  with  a  technique discovered by Jesús Arias, bypasing in fact the",13,10
  6454. DB " diskette drive controller.  Writing is a little slower than a normal disk but",13,10
  6455. DB " reading is faster.  The memory spent by 2MGUI  (usually, 17Kb in 1.44M)  is a",13,10
  6456. DB " little high.  These  disks are almost as reliable as 2M normal disks or 2MF/M",13,10
  6457. DB " ones,  but  their  design  is  not  as  suitable for use in real multitasking",13,10
  6458. DB " environs.  These  diskette  formats  work on most PC, XT or AT computers with",13,10
  6459. DB " high density drives and disk controllers.",13,10
  6460. DB "                                                        (2/5)  [PRESS ANY KEY]",1
  6461. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"               ",13,10,10
  6462. DB "        ──────────────────── OTHER SWITCHES SUPPORTED ARE ────────────────────",13,10
  6463. DB " /Q     Performs a quick format of two first tracks.  Useful to change logical",13,10
  6464. DB "        characteristics of a full non-defective already 2mgui-formatted disk.",13,10
  6465. DB " /L=lb  Sets the volume label of the disk (maximum of 11 characters).  It will",13,10
  6466. DB "        be accepted in either uppercase and lowercase.",13,10
  6467. DB " /V=lb  Sets an automatic sequencing of labels  (the  specified  one  must  be",13,10
  6468. DB "        number terminated).",13,10
  6469. DB " /TEST  Evals, with high accuracy, the disk capacity supported by the selected",13,10
  6470. DB "        disk drive, and also measures the drive rotation speed.  The test disk",13,10
  6471. DB "        doesn't need to be formatted and data stored will be lost (destructive",13,10
  6472. DB "        test). It can be used with /DD or /ED switches to select disk density;",13,10
  6473. DB "        by default, high density will be used. Also /NODMA can be selected.",13,10
  6474. DB " /B=n   Forzes a new track size  (perhaps  the  maximum track size reported by",13,10
  6475. DB "        the previous disk test).  So, you can employ all disk capacity of your",13,10
  6476. DB "        own drive.  These  disks can be READ without problem on any other disk",13,10
  6477. DB "        drives, but WRITING them in poorer drives will damage data stored.",13,10
  6478. DB " /G=n   Selects the anti-FIFO gap value.  The crude track size is the addition",13,10
  6479. DB "        of this value (by default, 20) and the size set with /B: a smaller GAP",13,10
  6480. DB "        lets you to increment /B but decreases disk reliability.",13,10
  6481. DB " /M=n   Sets the number of high density tracks in /DH format  (by default, 28;",13,10
  6482. DB "        which means the first third part of the disk).",13,10
  6483. DB " /DRON  Turns on inverse DISKCOPY support (the opposite is /DROFF).  Only must",13,10
  6484. DB "        be used /DRON or /DROFF if DISKCOPY recalibrates on each track.  /DRON",13,10
  6485. DB "        is set by default in DR-DOS 6 and Novell DOS 7.",13,10
  6486. DB "                                                        (3/5)  [PRESS ANY KEY]",1
  6487. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"               ",13,10,10
  6488. DB " /DWOFF Disables delayed-write cache (the opposite is /DWON).  By default, the",13,10
  6489. DB "        delayed write is active.  You can turn it off if you detect a conflict",13,10
  6490. DB "        with any other system software,  but  this is really unusual.  To copy",13,10
  6491. DB "        disks (DISKCOPY) without delayed write may take hours.",13,10
  6492. DB " /X=n   Value to shift the beginning of a track from the  previous  one,  when",13,10
  6493. DB "        changing the head selected shown in degrees (0-359°) of angular length",13,10
  6494. DB "        of the track (sector sliding /X), 55° by default.",13,10
  6495. DB " /Y=n   Similar to previous switch, but when changing the cylinder (90°).  Do",13,10
  6496. DB "        not modify /X or /Y without knowing how: they alter disk performance.",13,10
  6497. DB " /NODMA Turns off DMA mode. In DMA mode, QEMM needs a DMA=13 (1.44M) or DMA=25",13,10
  6498. DB "        (2.88M) switch, but EMM386 does not need it.  You can avoid this (or a",13,10
  6499. DB "        DMA frontier crossing problem) with this option:  2MGUI can work in AT",13,10
  6500. DB "        systems without using DMA; but in this way, it is less compatible with",13,10
  6501. DB "        some system configurations (but if works, the reliability is similar).",13,10
  6502. DB " /EMS   Only allowed with /NODMA, saves memory (uses 5 Kb) using EMS instead.",13,10
  6503. DB 10
  6504. DB " Copyright:",13,10
  6505. DB " ──────────",13,10
  6506. DB " The technology used by 2MGUI and the resulting disk format are, both,  public",13,10
  6507. DB " domain.  Any patent registered in any country with the technique of access to",13,10
  6508. DB " complete tracks will be void.  This program, however, is Copyright (C) of its",13,10
  6509. DB " author. It can be freely and without charge distributed;  the condition to be",13,10
  6510. DB " a registered user is the same that with 2M package (to send a postcard to the",13,10
  6511. DB " author).",13,10
  6512. DB "                                                        (4/5)  [PRESS ANY KEY]",1
  6513. DB 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10,10
  6514. DB " Some finally notes:",13,10
  6515. DB " ───────────────────",13,10
  6516. DB " - It is possible to run DISKCOPY into a 2MGUI drive, over any one disk format",13,10
  6517. DB "   available, but target diskette must be already formatted,  and  must  be of",13,10
  6518. DB "   the same physical characteristics and size as source one.  MS-DOS  DISKCOPY",13,10
  6519. DB "   (not DR-DOS one) fails on first execution over a new disk,  when  it is not",13,10
  6520. DB "   of the same type as the latest accessed the last time;  the  problem occurs",13,10
  6521. DB "   because DISKCOPY doesn't support that a device drive modifies,  on the fly,",13,10
  6522. DB "   it physical characteristics. If DISKCOPY returns an error execute it again;",13,10
  6523. DB "   but it's preferable to perform a DIR command over the drive before copying.",13,10
  6524. DB 10
  6525. DB " - 2MGUI performs a delayed-write  on  diskette drives (speeding up only 2MGUI",13,10
  6526. DB "   diskettes).  The  user must not extract the disk although system prompt has",13,10
  6527. DB "   already returned, until after at least a half second and a little more.",13,10
  6528. DB 10
  6529. DB " Important:",13,10
  6530. DB " ──────────",13,10
  6531. DB " - Under Windows 3, operations performed on 2MGUI disks under file manager may",13,10
  6532. DB "   appear to hang the system.  However, although mouse pointer does not answer",13,10
  6533. DB "   and keyboard seems to be locked,  the  system  has not necessarily crashed.",13,10
  6534. DB "   Wait for some seconds before resetting it.  Windows  95  is compatible with",13,10
  6535. DB "   2MGUI only in true MS-DOS sessions.",13,10
  6536. DB " - It is recommended to set BUFFERS=40 in CONFIG.SYS to improve performance.",13,10
  6537. DB 0
  6538.  
  6539. buffer_aux     DB    256 DUP (0)  ; buffer para alguna función del DOS/EMS
  6540.  
  6541. _PRINCIPAL     ENDS
  6542.  
  6543. tampila        EQU   2048         ; 2 Kb de pila son suficientes
  6544.  
  6545. _PILA          SEGMENT STACK 'STACK'
  6546.                DB    tampila DUP (?)
  6547. _PILA          ENDS
  6548.  
  6549.                END   main
  6550.